Php 如何更改PCRE regexp认为多行模式中的换行符?
使用PHP中的PCRE正则表达式,多行模式(Php 如何更改PCRE regexp认为多行模式中的换行符?,php,regex,preg-match,pcre,Php,Regex,Preg Match,Pcre,使用PHP中的PCRE正则表达式,多行模式(/m)允许^和$匹配源文本中行的开始和结束(以换行符分隔),以及源文本的开始和结束 这在Linux上使用\n(LF)作为换行符时效果很好,但在Windows上使用\r\n(CRLF)时失败 有没有办法改变PCRE认为的新线?或者允许它以与$匹配行/字符串结尾相同的方式匹配CRLF或LF 示例: $EOL = "\n"; // Linux LF $SOURCE_TEXT = "one{$EOL}two{$EOL}three{$EOL}four";
/m
)允许^
和$
匹配源文本中行的开始和结束(以换行符分隔),以及源文本的开始和结束
这在Linux上使用\n
(LF)作为换行符时效果很好,但在Windows上使用\r\n
(CRLF)时失败
有没有办法改变PCRE认为的新线?或者允许它以与$
匹配行/字符串结尾相同的方式匹配CRLF或LF
示例:
$EOL = "\n"; // Linux LF
$SOURCE_TEXT = "one{$EOL}two{$EOL}three{$EOL}four";
if (preg_match('/^two$/m',$SOURCE_TEXT)) {
echo 'Found match.'; // <<< RESULT
} else {
echo 'Did not find match!';
}
$EOL=“\n”//Linux LF
$SOURCE_TEXT=“一{$EOL}二{$EOL}三{$EOL}四”;
if(preg_match(“/^two$/m”,$SOURCE_TEXT)){
echo“找到匹配项”。;//
注意:答案只适用于较旧的PHP版本,当我编写它时,我不知道可用的序列和修饰符:\R
,(*BSR\u ANYCRLF)
和(*BSR\u UNICODE)
。请参见以下答案:
在PHP中,无法为PCRE正则表达式模式指定换行符序列。m
修饰符仅查找\n
。并且没有运行时设置可用于进行perl中可能进行的更改,但这不是PHP的选项
我通常只是在将字符串与preg\u match
等一起使用之前修改它:
$subject = str_replace("\r\n", "\n", $subject);
这可能不是你想要的,但可能会有所帮助
编辑:关于您添加到问题中的windows EOL示例:
$EOL = "\r\n"; // Windows CR+LF
$SOURCE_TEXT = "one{$EOL}two{$EOL}three{$EOL}four";
if (preg_match('/^two$/m',$SOURCE_TEXT)) {
echo 'Found match.';
} else {
echo 'Did not find match!'; // <<< RESULT
}
$EOL=“\r\n”//Windows CR+LF
$SOURCE_TEXT=“一{$EOL}二{$EOL}三{$EOL}四”;
if(preg_match(“/^two$/m”,$SOURCE_TEXT)){
echo“找到匹配项”;
}否则{
echo“未找到匹配项!”;//这很奇怪,我不认为$
(带m修饰符)关心是否有\n
或\r\n
作为新行
要测试这一点,可以在$
\s
之前添加\s*
,然后在\n
之前添加\r
,如果这确实是问题所在。
只要在行尾有额外的空格没有问题,就不会有任何问题。您是否尝试了(*CRLF)
和相关的修饰符?它们在维基百科上有详细说明(在换行/换行选项下),在我的测试中似乎做了正确的事情。即“/(*CRLF)^两个$/m'
应该与windows的新行相匹配。\r\n
也应该与linux和windows相匹配,但我还没有对此进行测试。这一切都取决于您的数据来自何处-外部和不受控制的源可能会提供相当混乱的数据。对于那些试图摆脱这种情况的人来说,这是一个提示(或至少解决)在多行模式(/m)下,在任何行的末尾($)正确匹配模式的问题
我也不认为这有什么关系,但我的正则表达式似乎无法匹配eol\r\n
。行的开头匹配正常。我假设这是因为结尾字符是\r
,而不是\n
?我在问题中添加了一个示例,显示了这一点。感谢\s*
>建议-这似乎确实解决了这个问题。我不认为文档对此特别清楚,它只是说:“如果主题字符串中没有“\n”字符,或者模式中没有出现“^”或“$,则设置此修饰符无效。”它明确指出,\n
是(唯一的)由m
修饰符反映的换行字符序列。我也为您添加的代码的答案添加了一些解释。是的,这似乎确实是这样;感谢您的澄清。但是,我不相信文档中明确说明了这一点,除非您有其他来源?您提供给的链接,来自w我上面引用的这句话并没有清楚地说明这一点,尽管它可能被解释为粗略地推断这一点。@w3d:我不明白该争论什么。它指定了哪个字符作为m
修饰符的行尾。你甚至引用了它。因为\n
是唯一有区别的字符,你怎么能您认为除\n
之外的另一个字符也会有所不同吗?为什么文档只列出子集而不是超集?可能是这样,但这只是猜测。从我在那里读到的内容来看,我不希望\r\n
被视为以多行模式结束的行。特别是在编写\n
被视为行尾。是的,当在模式开头指定时,这也适用于我(包括(*ANYCRLF)
)。请注意,这些修饰符从PCRE 7.3开始就可用,它是。
$EOL = "\r\n"; // Windows CR+LF
$SOURCE_TEXT = "one{$EOL}two{$EOL}three{$EOL}four";
if (preg_match('/^two$/m',$SOURCE_TEXT)) {
echo 'Found match.';
} else {
echo 'Did not find match!'; // <<< RESULT
}
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
// C 3 p 0 _
$pat1='/\w$/mi'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi'; // Slightly better
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org when used improperly
$pat4='/\w(?=\R)/i'; // Much better with allowed lookahead assertion (just to detect without capture) without multiline (/m) mode; note that with alternative for end of string ((?=\R|$)) it would grab all 7 elements as expected
$pat5='/\w\v?$/mi';
$pat6='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment (described on pcre.org and en.wikipedia.org)
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
$t=preg_match_all($pat6, $str, $m6);
echo $str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
."\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
."\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
."\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
."\n5 !!! $pat5 ($s): ".print_r($m5[0], true)
."\n6 !!! $pat6 ($t): ".print_r($m6[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 and $pat4 (\R), $pat5 (\v) and altered newline option in $pat6 ((*ANYCRLF)) - for some applications at least.
/* The code above results in the following output:
ABC ABC
123 123
def def
nop nop
890 890
QRS QRS
~-_ ~-_
1 !!! /\w$/mi (3): Array
(
[0] => C
[1] => 0
[2] => _
)
2 !!! /\w\r?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
3 !!! /\w\R?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
4 !!! /\w(?=\R)/i (6): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
)
5 !!! /\w\v?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
6 !!! /(*ANYCRLF)\w$/mi (7): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
[6] => _
)
*/
?>