对于这个问题,我找到了几个部分的答案,但没有一个能满足我的所有需求…
我试图解析用户生成的字符串,就好像它是一系列php函数参数来确定参数的数量:
这个字符串:
$arg1,$arg2='ABC,DEF',$arg3="GHI'",JKL",$arg4=array(1,'2)',"3'"),")
将作为函数的参数插入:
function my_function( [insert string here] ){ ... }
我需要解析逗号上的字符串,考虑单引号和双引号、圆括号、转义引号和圆括号来创建一个数组:
array(4) {
[0] => $arg1
[1] => $arg2='ABC,DEF'
[2] => $arg3="GHI'",JKL"
[3] => $arg4=array(1,'2)',"3'"),")
}
任何正则表达式或解析器函数的帮助,以完成这是感激的!
使用传统的csv工具是不可能解决这个问题的,因为有多个字符能够保护字符串的部分。使用preg_split
是可能的,但会导致非常复杂和低效的模式。所以最好的方法是用preg_match_all
。然而,有几个问题需要解决:
- 如果需要,必须忽略引号或括号内的逗号(视为没有特殊含义的字符,而不是分隔符)
- 你需要提取参数,但你需要检查字符串是否有好的格式,否则匹配结果可能是完全错误的!
对于第一点,您可以定义子模式来描述每种情况:用引号括起来的部分,括号括起来的部分,以及能够匹配完整参数的更通用的子模式,并且在需要时使用前面两个子模式。
请注意,括号子模式也需要引用通用子模式,因为它可以包含任何内容(也可以包含逗号)。
第二个点可以使用'G
锚来解决,确保所有匹配都是连续的。但是您需要确保已经到达字符串的末尾。为此,您可以在主模式的末尾添加一个可选的空捕获组,该捕获组仅在字符串'z
末尾的锚成功时创建。
$subject = <<<'EOD'
$arg1,$arg2='ABC,DEF',$arg3="GHI'",JKL",$arg4=array(1,'2)',"3'"),")
EOD;
$pattern = <<<'EOD'
~
# named groups definitions
(?(DEFINE) # this definition group allows to define the subpatterns you want
# without matching anything
(?<quotes>
' [^''']*+ (?s:''.[^''']*)*+ ' | " [^"'']*+ (?s:''.[^"'']*)*+ "
)
(?<brackets> '( 'g<content> (?: ,+ 'g<content> )*+ ') )
(?<content> [^,'"()]*+ # ' # (<-- comment for SO syntax highlighting)
(?:
(?: 'g<brackets> | 'g<quotes> )
[^,'"()]* # ' #
)*+
)
)
# the main pattern
(?: # two possible beginings
'G(?!'A) , # a comma contiguous to a previous match
| # OR
'A # the start of the string
)
(?<param> 'g<content> )
(?: 'z (?<check>) )? # create an item "check" when the end is reached
~x
EOD;
$result = false;
if ( preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER) &&
isset(end($matches)['check']) )
$result = array_map(function ($i) { return $i['param']; }, $matches);
else
echo 'bad format' . PHP_EOL;
var_dump($result);
演示您可以在,$
处拆分参数字符串,然后将$
附加到数组值后面:
$args_array = explode(',$', $arg_str);
foreach($args_array as $key => $arg_raw) {
$args_array[$key] = '$'.ltrim($arg_raw, '$');
}
print_r($args_array);
输出:(
[0] => $arg1
[1] => $arg2='ABC,DEF'
[2] => $arg3="GHI'",JKL"
[3] => $arg4=array(1,'2)',"3'"),")
)
如果你想使用正则表达式,你可以这样做:
(.+?)(?:,(?='$)|$)
演示工作Php代码:
$re = '/(.+?)(?:,(?='$)|$)/';
$str = "'$arg1,'$arg2='ABC,DEF','$arg3='"GHI'",JKL'",'$arg4=array(1,'2)','"3'"),'")'n";
preg_match_all($re, $str, $matches);
匹配信息:
MATCH 1
1. [0-5] `$arg1`
MATCH 2
1. [6-21] `$arg2='ABC,DEF'`
MATCH 3
1. [22-39] `$arg3="GHI'",JKL"`
MATCH 4
1. [40-67] `$arg4=array(1,'2)',"3'"),")`