首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  PHP

正则/^[a-z]+$/只有 PHP 匹配换行符,这算是 PHP 的 bug 么

  •  3
     
  •   sunweiqiang8 · 170 天前 · 2218 次点击
    这是一个创建于 170 天前的主题,其中的信息可能已经有所发展或是发生改变。
    # php 7.2.16
    var_dump(preg_match("/^[a-z]+$/", "abc\n"));
    #int(1)
    
     # javascript
    var reg = /^[a-z]+$/;
    console.log(reg.test("abc\n"));
    # 打印的是 false
    
    # java(jdk11)
    System.out.println(Pattern.matches("^[a-z]+$", "abc\n"));
    # 打印的是 false
    
    第 1 条附言  ·  169 天前
    单引号(')下的\n 不会被转义,请各位不要再讨论单引号下\n 的话题了,没有意义。
    第 2 条附言  ·  169 天前
    找到答案了,PHP 中正则特性,各位 PHPer 以后写正则匹配单行时记得加上修饰符 D

    https://www.regular-expressions.info/anchors.html
    "Because Perl returns a string with a newline at the end when reading a line from a file, Perl's regex engine matches $ at the position before the line break at the end of the string even when multi-line mode is turned off. Perl also matches $ at the very end of the string, regardless of whether that character is a line break. So ^\d+$ matches 123 whether the subject string is 123 or 123\n."

    https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

    "D (PCRE_DOLLAR_ENDONLY)
    If this modifier is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this modifier, a dollar also matches immediately before the final character if it is a newline (but not before any other newlines). This modifier is ignored if m modifier is set. There is no equivalent to this modifier in Perl."
    33 回复  |  直到 2019-06-21 14:11:15 +08:00
        1
    yuwangG   169 天前
    你对比的不是一个东西, 你把 var_dump(preg_match("/^[a-z]+$/", "abc\n"));
    #int(1)
        2
    yuwangG   169 天前
    换成 var_dump(preg_match("/^[a-z]+$/", 'abc\n')); 就会输出 #int(0)。 注意 PHP 双引号和单引号区别
        3
    no1xsyzy   169 天前   ♥ 1
    没自己用过 PHP,但我合理猜测是 $ 匹配到了 \n 的前面
        4
    no1xsyzy   169 天前
    自己->仔细
        5
    no1xsyzy   169 天前
    @yuwangG 你在说什么鬼,1 分钟的搜索引擎告诉我单引号下 \n 不是换行符。
        6
    back0893   169 天前
    @no1xsyzy php 里面还真不是 使用单引号那么就是 \n 的字符串
        7
    Youngxj   169 天前
    var_dump(preg_match("/^[a-z]+$/", 'abc\n'));
    输出的确实为 int(0),应该是 php 的双引号会把\n 解析掉,单引号是文本,所以不会解析掉
        8
    ben1024   169 天前
    单双引号
    $str = 'abc';
    var_dump(preg_match("/^[a-z]+$/", "{$str}\n"));
    int 1

    var_dump(preg_match("/^[a-z]+$/", 'abc\n'));
    int 0
        9
    sunweiqiang8   169 天前
    @yuwangG
    请先了解 PHP 单引号和双引号的区别
        10
    SakuraKuma   169 天前
    我寻思着一楼有啥问题??
    你把 match 出来的东西看看不就知道了。。
        11
    golden0125   169 天前
    @no1xsyzy 麻烦质疑前先自己测试一下
        12
    no1xsyzy   169 天前
    @back0893 https://tio.run/##[email protected]/fxr4go4CroCgzr0RBPTEpOSZP3RrKVbKyUoKzwVJKqFL2dv//AwA
    请?
    'abc\n' 是一个五字符的串,对应 list 是 '(#\a #\b #\c #\\ #\n) 或者说 '(97 98 99 92 110)
    "abc\n" 是一个四字符的串,对应 list 是 '(#\a #\b #\c #\newline) 或者说 '(97 98 99 10)
        13
    no1xsyzy   169 天前
    @golden0125 您测试了?见 #12。
        14
    wu1990   169 天前
    /(*CRLF)^[a-z]+$/
        15
    no1xsyzy   169 天前
    @golden0125 再来一个: https://tio.run/##[email protected]/fxr4go4CroCgzr0RBPTEpOSZP3RrKVbKyUoKzwVJKqFL2dv//AwA
        16
    ThirdFlame   169 天前
    是的 php 的 preg_match 中$ 可以命中字符串结尾 也可以命中 chr(10) , CTF 比赛经常会出现这个。
        17
    golden0125   169 天前
    @no1xsyzy PHP 初学者都知道的问题,双引号下\n 被转义了,单引号不会被转义,有这么难理解吗?
        18
    no1xsyzy   169 天前
    @wu1990 这个方法……是把换行符设置成 \r\n 才算吗?
        19
    leo108   169 天前
    @golden0125 建议看明白楼主的问题之后再来杠
        20
    no1xsyzy   169 天前
    @golden0125 我说的不是这个?
    #5
    > 单引号下 \n 不是换行符
        21
    zsdroid   169 天前   ♥ 5
    /^[a-z]+$/D

    php 正则用的是 Perl 兼容正则表达式

    $ 结尾处默认忽略回车

    加 D 就变成不忽略回车
        22
    golden0125   169 天前
    @no1xsyzy 你 @的 1 2 楼不也是说的单双引号的区别?

    "你在说什么鬼,1 分钟的搜索引擎告诉我单引号下 \n 不是换行符。"

    他说过单引号下 \n 是换行符?
        23
    sunweiqiang8   169 天前   ♥ 1
    @zsdroid
    是的,应该是 PHP 中独有的正则特性
    https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
        24
    golden0125   169 天前
    @leo108 麻烦你看明白我的问题后再来杠
        25
    no1xsyzy   169 天前   ♥ 1
    对了回到楼主的问题,看来不是 bug 是 feature ……
    PCRE 这套正则就是这么设计的,as spec。参考:<https://php.net/manual/zh/reference.pcre.pattern.modifiers.php>
    『默认情况下,PCRE 认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行), "行首"元字符 (^) 仅匹配字符串的开始位置, 而"行末"元字符 ($) 仅匹配字符串末尾, 或者最后的换行符(除非设置了 D 修饰符)。』
    所以正确的做法是加修饰符 D,样例:
    https://tio.run/##[email protected]/fxr4go4CroCgzr0ShLLEoPqU0t0CjoCg1PT43sSQ5Q0NJPy46UbcqVltFX0lHQSkxKVlJU9OaOA0uUB0xeWA99nb//wMA
        26
    no1xsyzy   169 天前
    @golden0125 看楼主标题 “只有 PHP 匹配换行符”。
    而 #1#2 答非所问,要问个换行符相关的问题,结果回答是 “把换行符去掉就行了”。你觉得这是回答?
        27
    yuwangG   169 天前
    @zsdroid 是的,学习了~ thanks
        28
    golden0125   169 天前
    @no1xsyzy 我没看到他回答过 “把换行符去掉就行了” 他回答的很清楚,注意单双引号的区别
        29
    zarte   169 天前
    @zsdroid
    终于等到一个解决的回复了。
        30
    yuwangG   169 天前
    @no1xsyzy 确实, 理解题目出现了偏差,尴尬~
        31
    no1xsyzy   169 天前
    @golden0125 把 "\n" 换成 '\n' 不是把换行符去掉?换成了 #\\ 和 #\n。
    你说说 'abc\n' 里哪来的换行符?换成单引号哪里符合楼主的提问?
    况且那个 "abc\n" 实际使用基本不会是字面量而是字符串变量( Pattern 是变量而待匹配字符串是常量的情况比较少,而且这种情况一般也不会产生换行结尾的),这种情况下你怎么改单引号?
    没理了还强行杠?
        32
    dyllen   169 天前
    @sunweiqiang8 不是独有吧,php 的文档里面明确说明的 php 实现的正则是和 perl 一样的,那估计 perl 里面也是这样的。
        33
    sunweiqiang8   169 天前
    @dyllen

    修饰符 D 的描述最后一行:
    There is no equivalent to this modifier in Perl
    在 Perl 中没有与此修饰符等效的东西
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1700 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 29ms · UTC 01:33 · PVG 09:33 · LAX 17:33 · JFK 20:33
    ♥ Do have faith in what you're doing.