PHP: explode but ignore escaped delimiter

I have a flatfile database and this data is separated by delimiters.

I allow people to use a separator in the input, but I'm sure to avoid it with \ in advance.

The problem is that my explode() function is still trying to separate the escaped delimiters, so how can I say to ignore them?

+6
source share
4 answers

Use preg_split instead. Using a regular expression, you can match a metric only if it is not preceded by a backslash.

Edit:

 preg_split('~(?<!\\\)' . preg_quote($delimeter, '~') . '~', $text); 
+7
source

None of the solutions here should handle any number of control characters, or they leave them at the output. Here is an alternative:

 function separate($string, $separator = '|', $escape = '\\') { if (strlen($separator) != 1 || strlen($escape) != 1) { trigger_error(__FUNCTION__ . ' requires delimiters to be single characters.', E_USER_WARNING); return; } $segments = []; $string = (string) $string; do { $segment = ''; do { $segment_length = strcspn($string, "$separator$escape"); if ($segment_length) { $segment .= substr($string, 0, $segment_length); } if (strlen($string) <= $segment_length) { $string = null; break; } if ($escaped = $string[$segment_length] == $escape) { $segment .= (string) substr($string, ++$segment_length, 1); } $string = (string) substr($string, ++$segment_length); } while ($escaped); $segments[] = $segment; } while ($string !== null); return $segments; } 

This will process a raw string like foo\|ba\r\\|baz| in foo|bar\ , baz and an empty string.

If you want to keep the escape character in the output, you have to change the function.

Note: this will have unpredictable behavior if you use the mb function overload .

+1
source

Input data

 key1=val1;key2=val2start\;val2end;key3=val3\\;key4=val4\\\;key5=val5\\\\;key6=val6 

REGEX

 /(.*?[^\\](\\\\)*?);/ 

Example

 <?php $data="key1=val1;key2=val2start\\;val2end;key3=val3\\\\;key4=val4\\\\\\;key5=val5\\\\\\\\;key6=val6"; $regex='/(.*?[^\\\\](\\\\\\\\)*?);/'; preg_match_all($regex, $data.';', $matches); print_r($matches[1]); 

Exit

 Array ( [0] => key1=val1 [1] => key2=val2start\;val2end [2] => key3=val3\\ [3] => key4=val4\\\;key5=val5\\\\ [4] => key6=val6 ) 
0
source

preg_split will definitely give you what you want. However, I wrote this little snippet and it seems to work well. If you do not want to use preg_split, follow these steps:

 $delim = ','; $string = "Hello,World,This\\,is escaped,This is not"; $array = explode($delim, $string); $finalArray = array(); var_dump($array); for($i = 0; $i < count($array); $i++) { $strToPush = $array[$i]; while("\\" == substr($array[$i], -1)) { $i++; $strToPush .= $delim . $array[$i]; } array_push($finalArray, $strToPush); } var_dump($finalArray); 

Which gives the result:

an array
0 => string 'Hello' (length = 5)
1 => string "World" (length = 5)
2 => string 'This \' (length = 5)
3 => string 'escaped' (length = 10)
4 => the string "This is not" (length = 11)

an array
0 => string 'Hello' (length = 5)
1 => string "World" (length = 5)
2 => string 'This \, escaped' (length = 16)
3 => the string "This is not" (length = 11)

-1
source

Source: https://habr.com/ru/post/903839/


All Articles