我有一个平面文件数据库,它是由分隔符分隔的数据。
我允许人们在他们的输入中使用分隔符,但我确保事先用'
转义。
问题是我的explode()
函数仍然试图分割转义的分隔符,那么我如何告诉它忽略它们?
使用preg_split代替。通过使用正则表达式,只有当分隔符前面没有反斜杠时,才能匹配分隔符。
编辑:preg_split('~(?<!''')' . preg_quote($delimeter, '~') . '~', $text);
这里的解决方案都不能正确处理任何数量的转义字符,或者将它们留在输出中。这是另一个选项:
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;
}
这将处理原始字符串如foo'|ba'r''|baz|
为foo|bar'
, baz
,和一个空字符串。
如果您希望在输出中保留转义字符,则必须修改该函数。
输入数据
key1=val1;key2=val2start';val2end;key3=val3'';key4=val4''';key5=val5'''';key6=val6
REGEX /(.*?[^'']('''')*?);/
<?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]);
输出Array
(
[0] => key1=val1
[1] => key2=val2start';val2end
[2] => key3=val3''
[3] => key4=val4''';key5=val5''''
[4] => key6=val6
)
<?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]);
Array
(
[0] => key1=val1
[1] => key2=val2start';val2end
[2] => key3=val3''
[3] => key4=val4''';key5=val5''''
[4] => key6=val6
)
您会发现这个解决方案比使用regex处理大字符串更有用。我使用了一个流来允许使用fgetcsv
,这是针对这种事情进行优化的。
<?php
function escaped_explode($string,$delimit,$escape=NULL,$enclosure=NULL,$max_line_length=0){
$r=[];
$stream = fopen('php://memory','r+');
fwrite($stream, $string);
rewind($stream);
while (($data = fgetcsv($stream,$max_line_length,$delimit,$enclosure,$escape)) !== FALSE)
$r=array_merge($r,$data);
fclose($stream);
return $r;
}
?>
用法:
$pipelined_values = escaped_explode($source,'|','''');
这也很方便,因为您可以选择使用引号等附件,而不是仅使用转义字符。如果您遇到解析某人的JSON值或其他语法时,这是很好的,因为您既可以括起来,也可以转义。
$source= <<<JSON
'{ "key":"val", "n":0}',
'{ "key":"val", "n":1, "name": "French du''Name" }',
'{ "key":"val", "n":2}'
JSON;
可以被解释
<?php
$objects=[];
$raw= escaped_explode($source, ',', '''', "'");
foreach($raw as $r)
$objects[] = json_decode($r);
?>