Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何更改PCRE regexp认为多行模式中的换行符?_Php_Regex_Preg Match_Pcre - Fatal编程技术网

Php 如何更改PCRE regexp认为多行模式中的换行符?

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";

使用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";
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] => _
)
 */
?>