I have a series of strings of numbers of different lengths that I need to split into chunks of 2 characters. The last chunk should be 3 characters long, if it would be 1 character long.
For example, 22334455
needs to become 22 33 44 55
, but 2233444
needs to become 22 33 444
.
I have:
implode(" ", str_split($string, 2));
but that returns 22 33 44 4
.
What can I do?
I have thought of:
str_split
returnsimplode
but that seems extremely complicated for something that a human would approach like this:
That's a recursive function and in PHP might perhaps look something like:
$chunks = array();
while(strlen($string) > 3) {
$chunks[] = substr($string, 0, 2);
$string = substr($string, 2);
}
$chunks[] = $string;
implode(" ", $chunks);
But that still seems overly complicated compared to a human who would just evaluate, cut, evaluate, cut, evaluate, not cut
.
Is there a more straightforward, less roundabout way?
You might use a regex to split on:
\S\S\K(?=\S\S)
The regex matches:
\S\S
Match 2 non whitespace characters\K
Forget what is matched so far (this will result in the position to split on)(?=\S\S)
Assert that there are 2 non whitespace characters to the rightIf you only want to match digits, you can use \d
instead of \S
See the matches on regex 101 and a PHP demo
$data = [
"",
"2",
"22",
"223",
"2233",
"22334",
"223344",
"2233444",
"22334455"
];
$pattern = '/\S\S\K(?=\S\S)/';
foreach ($data as $item) {
var_export(preg_split($pattern, $item));
}
Output
array (
0 => '',
)array (
0 => '2',
)array (
0 => '22',
)array (
0 => '223',
)array (
0 => '22',
1 => '33',
)array (
0 => '22',
1 => '334',
)array (
0 => '22',
1 => '33',
2 => '44',
)array (
0 => '22',
1 => '33',
2 => '444',
)array (
0 => '22',
1 => '33',
2 => '44',
3 => '55',
)
Wanting to split the string is an XY Problem in the first place. You don't need a temporary array. Just inject the spaces where they are needed -- only at the zero-width position between two 2-digit substrings. Match 2 digits, forget that match (holding a zero-width position in the string), lookahead for 2 more digits. Demo
echo preg_replace(
'/\d{2}\K(?=\d{2})/',
' ',
$string
);
/(\d{2})\K(?=(?1))/
and
/\d\d\K(?=\d\d)/
also work the same.
You can even skip-fail the last 2-3 digits in the string then inject the spaces after all other pairs of digits. Demo
echo preg_replace(
'/\d{2,3}$(*SKIP)(*FAIL)|\d{2}\K/',
' ',
$tests
);
If you don't like \K
in the pattern, a backreference in the replacement will be necessary.
echo preg_replace('/\d\d(?=\d\d)/', '$0 ', $string);`
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With