$不匹配位于最后一个字符的换行符之前的位置

时间:2012-08-15 13:34:07

标签: php regex

$不匹配作为最后一个字符的换行符之前的位置。

理想情况下,/ 1... $ /应匹配,但匹配的情况与/1 / $ /似乎是错误的。

可能是什么原因?

PHP doc还说一个美元字符($)是一个断言,只有当前匹配点位于主题字符串的末尾时,或者紧接在作为最后一个字符的换行符之前,该断言才为TRUE。 string(默认情况下)。

$subject = 'abc#
123#
';
$pattern = '/1...$/';
preg_match_all($pattern,$subject,$matches); // no match

更新 由于换行符的\ r \ n格式,我怀疑有额外的点。 我做了以下实验并看到了一些提示。

$pattern = '/1...(.)$/';

echo bin2hex($matches[1]); // 28

28似乎等于\ r \ n(CR)所以基本上$在\ n之前匹配\ n而不是\ r \ n之前,这可能是我问题的原因。

enter image description here

打开不可打印字符后的图像

3 个答案:

答案 0 :(得分:3)

问题是由于窗口文件和linux文件的不同换行符表示

为什么会出现这个问题:

  • 我在窗口中创建了php文件并转移到安装了PHP的linux。
  • Windows使用\ r \ n来表示换行符和linux \ n ==>这就是为什么最初它需要额外的点来匹配。

以下实验证实了同样的情况:

$subject = 'abc#
123#
';
$pattern = '/1...(.)$/';
preg_match_all($pattern,$subject,$matches);
echo bin2hex($matches[1]); // 28 
// 28 is equivalent of \r or CR(carriage return)

在linux系统中创建新文件,/ 1... $ /捕获匹配:)

我希望如果遇到同样的问题,这会节省一些人的时间。

答案 1 :(得分:2)

你的字符串是多行的。默认情况下,正则表达式不会做多行。您必须添加m修饰符才能实现此目的。

例如:

/1...$/m

答案 2 :(得分:0)

我已经被困在这个问题上两天了。我做了很多测试,找到了这背后的任何逻辑,因为这完全取决于数据的来源(内部和受控对外部和不受控制)。在我的例子中,它是我的网站上的输入字段(<textarea>),可从各种浏览器(和各种操作系统)获得,并且在JavaScript中没有模式测试/匹配/检查的问题。以下是那些试图在多行模式(/ m)的任何行的末尾($)正确匹配模式的问题(或至少解决)的人的提示。

<?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] => _
)
 */
?>

不幸的是,我无法访问使用最新PHP版本的服务器 - 我的本地PHP为5.3.8,而我的公共主机PHP版本为5.2.17。