Skip to content

Instantly share code, notes, and snippets.

@pospi
Created September 24, 2013 01:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pospi/6679400 to your computer and use it in GitHub Desktop.
Save pospi/6679400 to your computer and use it in GitHub Desktop.
Like PHP's implode() and explode(), but lets you escape the delimiters for splitting the strings with.
<?php
/**
* Same as implode, but escape the separator when it exists in the array elements being imploded
* If the separator is longer than 1 character, only the first character need be escaped (not every character of the delimiter).
*
* @param string $sep delimiter to stich the array together with
* @param array $arr array to combine
* @param char $escape escape character to escape any found delimiters with
* @return imploded string
*
* @author Sam Pospischil <pospi@spadgos.com>
*/
function escapedimplode($sep, $arr, $escape = '\\') {
if (!is_array($arr)) {
return false;
}
foreach ($arr as $k => $v) {
$arr[$k] = str_replace($sep, $escape . $sep, $v);
}
return implode($sep, $arr);
}
/**
* same as explode, but don't treat delimiters preceded by an escaped character as delimiters, and convert them in the output
* If the separator is longer than 1 character, only the first character need be escaped (not every character of the delimiter).
*
* @param string $sep boundary delimiter to split the input string on
* @param string $str string to explode
* @param char $escape escape character used to escape delimiters in the string
* @return exploded array, with delimiter escape characters removed
*
* @author Sam Pospischil <pospi@spadgos.com>
*/
function escapedexplode($sep, $str, $escape = '\\') {
$astr = str_split($str);
$result = array(); // final result array
$buffer = ''; // buffer for current array item match
$matchedBuffer = ''; // buffer for storing matched delimiters in case of a mismatch part-way
$wasEsc = false; // flag to ignore the current character if the previous one was an escape char
$sepLen = strlen($sep); // precomputed length of separator string, for efficiency
$matchNext = 0; // character index within separator to attempt to match next
foreach ($astr as $char) {
if ($matchNext >= $sepLen) { // full separator has been matched, store and continue
$result[] = str_replace($escape . $sep, $sep, $buffer);
$buffer = '';
$matchedBuffer = '';
$matchNext = 0;
}
$nextChar = substr($sep, $matchNext, 1); // get next character to match
if ($char == $nextChar && !$wasEsc) { // partial separator match, keep matching
$matchNext++;
$matchedBuffer .= $char;
} else if ($matchNext > 0) { // matched partially but not completely, add matched chars to buffer
$buffer .= $matchedBuffer;
$matchNext = 0;
} else {
$buffer .= $char; // this isnt a separator, add to buffer
}
if ($char == $escape && $matchNext == 0) { // detect escape characters and flag that the next character *cannot* match
$wasEsc = true;
continue;
}
$wasEsc = false; // otherwise reset the escape character flag
}
// add any remaining buffered chars as the last element
if ($buffer || $matchedBuffer) {
$result[] = str_replace($escape . $sep, $sep, $buffer . $matchedBuffer);
}
return $result;
}
@pupi1985
Copy link

Maybe I'm not using this the way it is expected but it doesn't seem to work for this scenario:

$array1 = array('one\\', 'two');
$result = $this->escapedimplode(';', $array1);
echo $result . PHP_EOL;
print_r($this->escapedexplode(';', $result));

The expected output is:

one\;two
Array
(
    [0] => one\
    [1] => two
)

And the actual output is:

one\;two
Array
(
    [0] => one;two
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment