如何扩展正则表达式以查找多个匹配项?
How to extend regex to find multiple matches?
这是我当前的正则表达式(用于解析 iCal 文件):
/(.*?)(?:;(?=(?:[^"]*"[^"]*")*[^"]*$))([\w\W]*)/
使用preg_match()
的当前输出是这样的:
//Output 1 - `preg_match()`
Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
[1] => VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
我想扩展我的正则表达式来输出这个(即找到多个匹配项):
//Output 2
Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
[1] => VALUE=DATE
[2] => RSVP=FALSE
[3] => LANGUAGE=en-gb
)
正则表达式应搜索每个不包含在带引号的子字符串中的分号,并将其作为匹配项提供。
不能只交换到 preg_match_all()
,因为给出了这个 不需要的 输出
//Output 3 - `preg_match_all()`
Array
(
[0] => Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London";VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
[1] => Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
)
[2] => Array
(
[0] => VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
)
您可以使用以下方式进行匹配:
(.*?(?:;|$))(?![^"]*")
见DEMO
或拆分为:
;(?![^"]*")
见DEMO
(.+?)(?:;(?=(?:[^"]*"[^"]*")*[^"]*$)|$)
尝试 this.See 演示。
您需要使用preg_match_all
来获取字符串的所有匹配项。
您使用的模式不是为获得多个结果而设计的,因为 [\w\W]*
匹配字符串末尾的所有内容。
但这只是你的问题之一,像这样设计的模式需要检查(对于每个冒号)引号的数量是奇数还是偶数,直到文件结束!:(?=(?:[^"]*"[^"]*")*[^"]*$)
。想象一下,使用这种前瞻性分析整个字符串的次数。
为避免此问题,您可以使用另一种方法,该方法不尝试查找冒号,而是尝试描述所有 不是 冒号的内容:所以你是查找不包含引号或冒号 + 引号的文本的每个部分,无论内容如何。
你可以使用这种模式:
$pattern = '~[^\r\n";]+(?:"[^"\\]*(?:\\.[^"\\]*)*"[^\r\n";]*)*~';
if (preg_match_all($pattern, $str, $matches))
print_r($matches[0]);
图案详情:
~ # pattern delimiter
[^\r\n";]+ #" # all that is not a newline, a double quote or a colon
(?: # non-capturing group: to include eventual quoted parts
" #"# a literal quote
[^"\\]* #"# all that is not a quote or a backslash
(?:\\.[^"\\]*)* #"# optional group to deal with escaped characters
" #"#
[^\r\n";]* #"#
)* # repeat zero or more times
~
这是我当前的正则表达式(用于解析 iCal 文件):
/(.*?)(?:;(?=(?:[^"]*"[^"]*")*[^"]*$))([\w\W]*)/
使用preg_match()
的当前输出是这样的:
//Output 1 - `preg_match()`
Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
[1] => VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
我想扩展我的正则表达式来输出这个(即找到多个匹配项):
//Output 2
Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
[1] => VALUE=DATE
[2] => RSVP=FALSE
[3] => LANGUAGE=en-gb
)
正则表达式应搜索每个不包含在带引号的子字符串中的分号,并将其作为匹配项提供。
不能只交换到 preg_match_all()
,因为给出了这个 不需要的 输出
//Output 3 - `preg_match_all()`
Array
(
[0] => Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London";VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
[1] => Array
(
[0] => TZID="Greenwich Mean Time:Dublin; Edinburgh; Lisbon; London"
)
[2] => Array
(
[0] => VALUE=DATE;RSVP=FALSE;LANGUAGE=en-gb
)
)
您可以使用以下方式进行匹配:
(.*?(?:;|$))(?![^"]*")
见DEMO
或拆分为:
;(?![^"]*")
见DEMO
(.+?)(?:;(?=(?:[^"]*"[^"]*")*[^"]*$)|$)
尝试 this.See 演示。
您需要使用preg_match_all
来获取字符串的所有匹配项。
您使用的模式不是为获得多个结果而设计的,因为 [\w\W]*
匹配字符串末尾的所有内容。
但这只是你的问题之一,像这样设计的模式需要检查(对于每个冒号)引号的数量是奇数还是偶数,直到文件结束!:(?=(?:[^"]*"[^"]*")*[^"]*$)
。想象一下,使用这种前瞻性分析整个字符串的次数。
为避免此问题,您可以使用另一种方法,该方法不尝试查找冒号,而是尝试描述所有 不是 冒号的内容:所以你是查找不包含引号或冒号 + 引号的文本的每个部分,无论内容如何。
你可以使用这种模式:
$pattern = '~[^\r\n";]+(?:"[^"\\]*(?:\\.[^"\\]*)*"[^\r\n";]*)*~';
if (preg_match_all($pattern, $str, $matches))
print_r($matches[0]);
图案详情:
~ # pattern delimiter
[^\r\n";]+ #" # all that is not a newline, a double quote or a colon
(?: # non-capturing group: to include eventual quoted parts
" #"# a literal quote
[^"\\]* #"# all that is not a quote or a backslash
(?:\\.[^"\\]*)* #"# optional group to deal with escaped characters
" #"#
[^\r\n";]* #"#
)* # repeat zero or more times
~