preg_split
What Is preg_split() ? In simple terms: preg_split() cuts a string into pieces wherever a pattern matches. It works like explode() , but the separator can be a pattern — for example, "any comma, semic
What Is preg_split()?
In simple terms: preg_split() cuts a string into pieces wherever a pattern matches. It works like explode(), but the separator can be a pattern — for example, "any comma, semicolon, or run of spaces" instead of a single fixed character.
Technically: preg_split() returns an array of the substrings found between matches of the pattern. Flags control whether empty pieces are kept, whether the separators themselves are included, and whether offsets are returned. On error, it returns false.
Why Not Just Use explode()?
explode() needs one fixed separator. Real input is often less tidy:
php, mysql;laravel html
Here the items are separated by a comma and space, a semicolon, and several spaces. One preg_split() call handles all of them.
Syntax
preg_split(
string $pattern,
string $subject,
int $limit = -1,
int $flags = 0
): array|false
| Parameter | Meaning | |
|---|---|---|
$pattern | The separator pattern | |
$subject | The string to split | |
$limit | Maximum number of pieces (-1 or 0 \= no limit) | |
$flags | PREG_SPLIT_NO_EMPTY, PREG_SPLIT_DELIM_CAPTURE, PREG_SPLIT_OFFSET_CAPTURE (combinable with ` | `) |
Splitting on Multiple Separators
Example
<?php
$skills = 'php, mysql;laravel html';
print_r(preg_split('/[\s,;]+/', $skills));
Output
Array
(
[0] => php
[1] => mysql
[2] => laravel
[3] => html
)
[\s,;]+ matches any run of whitespace, commas, or semicolons. Using + treats a whole run (such as ", " or three spaces) as one separator, so no empty pieces are created between them.
Splitting Lines Regardless of Line Endings
<?php
$text = "first line\r\nsecond line\nthird line";
print_r(preg_split('/\R/', $text));
Output
Array
(
[0] => first line
[1] => second line
[2] => third line
)
\R matches any line break: Windows (\r\n), Unix (\n), and old Mac (\r). Text pasted into forms or uploaded files often mixes these, and explode("\n", ...) would leave stray \r characters at the end of lines.
The $limit Parameter
<?php
print_r(preg_split('/,/', 'a,b,c,d', 2));
Output
Array
(
[0] => a
[1] => b,c,d
)
With a limit of 2, the string is split at most once; the last piece contains the rest. This is useful for formats like key: value where the value itself may contain the separator.
Flags
PREG_SPLIT_NO_EMPTY — Remove Empty Pieces
<?php
$input = ',apple,,banana,';
print_r(preg_split('/,/', $input));
print_r(preg_split('/,/', $input, -1, PREG_SPLIT_NO_EMPTY));
Output
Array
(
[0] =>
[1] => apple
[2] =>
[3] => banana
[4] =>
)
Array
(
[0] => apple
[1] => banana
)
Leading, trailing, and doubled separators produce empty strings. PREG_SPLIT_NO_EMPTY removes them, and the result is re-indexed.
PREG_SPLIT_DELIM_CAPTURE — Keep the Separators
If the pattern contains a capturing group, the captured separator text is included in the result:
<?php
$expression = '12 + 4*3 - 5';
print_r(preg_split('/\s*([+\-*\/])\s*/', $expression, -1, PREG_SPLIT_DELIM_CAPTURE));
Output
Array
(
[0] => 12
[1] => +
[2] => 4
[3] => *
[4] => 3
[5] => -
[6] => 5
)
The expression is split into numbers and operators — a simple tokenizer. \s* around the group absorbs optional spaces, so they are not part of any token. Inside the character class, - and / are escaped because they have special meaning there (range and delimiter).
PREG_SPLIT_OFFSET_CAPTURE — Where Each Piece Starts
<?php
print_r(preg_split('/\s+/', 'one two three', -1, PREG_SPLIT_OFFSET_CAPTURE));
Output
Array
(
[0] => Array
(
[0] => one
[1] => 0
)
[1] => Array
(
[0] => two
[1] => 4
)
[2] => Array
(
[0] => three
[1] => 9
)
)
Each piece comes with its starting byte offset in the original string, which is useful for highlighting or editing text in place.
Splitting With Lookarounds
A pattern made only of lookarounds matches a position (zero characters), so the string is split without removing anything.
CamelCase to Words
<?php
$words = preg_split('/(?=[A-Z])/', 'getUserProfileName', -1, PREG_SPLIT_NO_EMPTY);
echo implode(' ', $words) . "\n";
echo strtolower(implode('_', $words)) . "\n";
Output
get User Profile Name
get_user_profile_name
(?=[A-Z]) matches the position before each uppercase letter. PREG_SPLIT_NO_EMPTY prevents an empty first piece when the string starts with an uppercase letter.
Sentences
<?php
$text = 'PHP is popular. Is it easy to learn? Yes! It powers many websites.';
print_r(preg_split('/(?<=[.!?])\s+/', $text));
Output
Array
(
[0] => PHP is popular.
[1] => Is it easy to learn?
[2] => Yes!
[3] => It powers many websites.
)
The lookbehind (?<=[.!?]) keeps the punctuation at the end of each sentence; only the whitespace after it is removed. (Abbreviations such as "e.g." would also be treated as sentence ends; natural language processing needs more advanced tools.)
Splitting Into Characters
<?php
$word = 'Café';
echo count(str_split($word)) . " pieces with str_split()\n";
echo implode(' | ', preg_split('//u', $word, -1, PREG_SPLIT_NO_EMPTY)) . "\n";
echo implode(' | ', mb_str_split($word)) . "\n";
Output
5 pieces with str_split()
C | a | f | é
C | a | f | é
str_split()splits by bytes, breaking the two-byteéinto invalid fragments.preg_split('//u', ...)splits between every UTF-8 character. The empty pattern matches every position;umakes the positions character-based.mb_str_split()(PHP 7.4+) does the same more directly and is the recommended choice.
For scripts with combining marks (such as Tamil or Hindi), a "character" as users perceive it may consist of several code points. preg_match_all('/\X/u', $text, $m) collects each visible character (an extended grapheme cluster) in $m[0], and grapheme_str_split() (PHP 8.4+, intl extension) does this directly.
Practical Example: Normalizing Tag Input
Users type tags in many ways — with commas, semicolons, extra spaces, duplicates, and mixed case:
<?php
function parseTags(string $input, int $maxTags = 10): array
{
$parts = preg_split('/[\s,;]+/u', $input, -1, PREG_SPLIT_NO_EMPTY);
if ($parts === false) {
return [];
}
$tags = array_map(fn(string $tag): string => mb_strtolower($tag), $parts);
$tags = array_filter($tags, fn(string $tag): bool => mb_strlen($tag) <= 30);
return array_slice(array_values(array_unique($tags)), 0, $maxTags);
}
print_r(parseTags(' PHP, MySQL;laravel,,php Web-Dev ; '));
Output
Array
(
[0] => php
[1] => mysql
[2] => laravel
[3] => web-dev
)
Step-by-Step Explanation
preg_split()withPREG_SPLIT_NO_EMPTYsplits on any run of separators and drops empty pieces caused by leading, trailing, or doubled separators.- A
falseresult (for example, invalid UTF-8 withu) is handled instead of passed on. - Tags are lowercased with
mb_strtolower(), soPHPandphpbecome identical. - Overly long tags are discarded, duplicates are removed, and the list is limited to
$maxTagsitems.
Hyphens are not separators here, so Web-Dev stays one tag.
preg_split() vs explode() vs str_getcsv()
| Function | Use When |
|---|---|
explode() | A single, fixed separator (faster) |
preg_split() | Several separators, variable whitespace, or position-based splitting |
str_getcsv() / fgetcsv() | CSV data with quoted fields ("Chennai, TN" must stay one field) |
mb_str_split() | Splitting text into characters |
Common Mistakes
Producing Empty Pieces
Effect: Empty strings in the result from leading, trailing, or repeated separators.
Fix: Use + in the pattern and PREG_SPLIT_NO_EMPTY.
Splitting CSV With a Regex
Effect: Commas inside quoted values break the fields.
Fix: Use str_getcsv() or fgetcsv().
Forgetting the u Modifier for Text
Effect: Character-based splitting breaks multi-byte characters.
Fix: Add u, or use mb_str_split().
Expecting Separators in the Result Without a Group
Effect: PREG_SPLIT_DELIM_CAPTURE has no effect.
Fix: Wrap the separator in a capturing group.
Not Checking for false
Effect: Errors are passed on as false, causing type errors later.
Fix: Check the result before using it.
Best Practices
- Use
explode()for fixed separators andpreg_split()when separators vary. - Combine
+quantifiers withPREG_SPLIT_NO_EMPTYfor messy user input. - Use
\Rfor line splitting andmb_str_split()for characters. - Use
PREG_SPLIT_DELIM_CAPTUREfor simple tokenizers. - Normalize, de-duplicate, and limit the resulting pieces when they come from users.
Official reference: https\://www.php.net/manual/en/function.preg-split.php