代码之家  ›  专栏  ›  技术社区  ›  JoelFan

匹配空格,但不匹配换行符

  •  230
  • JoelFan  · 技术社区  · 14 年前

    我有时想匹配空白而不是换行符。

    到目前为止,我一直在求助于 [ \t] . 有没有不那么尴尬的方法?

    6 回复  |  直到 5 年前
        1
  •  154
  •   Borodin    8 年前

    Perl 5.10及更高版本支持辅助的垂直和水平字符类, \v \h 以及一般的空白字符类 \s

    最干净的解决方案是使用 水平空白 字符类 h . 这将匹配来自ASCII集的制表符和空格、扩展ASCII的非中断空格或任何这些Unicode字符。

    U+0009 CHARACTER TABULATION
    U+0020 SPACE
    U+00A0 NO-BREAK SPACE (not matched by \s)
    
    U+1680 OGHAM SPACE MARK
    U+2000 EN QUAD
    U+2001 EM QUAD
    U+2002 EN SPACE
    U+2003 EM SPACE
    U+2004 THREE-PER-EM SPACE
    U+2005 FOUR-PER-EM SPACE
    U+2006 SIX-PER-EM SPACE
    U+2007 FIGURE SPACE
    U+2008 PUNCTUATION SPACE
    U+2009 THIN SPACE
    U+200A HAIR SPACE
    U+202F NARROW NO-BREAK SPACE
    U+205F MEDIUM MATHEMATICAL SPACE
    U+3000 IDEOGRAPHIC SPACE
    

    这个 垂直空间 模式 V 不太有用,但与这些字符匹配

    U+000A LINE FEED
    U+000B LINE TABULATION
    U+000C FORM FEED
    U+000D CARRIAGE RETURN
    U+0085 NEXT LINE (not matched by \s)
    
    U+2028 LINE SEPARATOR
    U+2029 PARAGRAPH SEPARATOR
    

    有七个垂直空格字符匹配 V 和18个水平的,匹配的 h . 的S 匹配23个字符

    所有空白字符都是 垂直的 水平的 没有重叠,但它们不是适当的子集,因为 h 还匹配u+00a0不间断空格,以及 V 也匹配下一行的U+0085,两者都不匹配 的S

        2
  •  300
  •   Greg Bacon    5 年前

    使用双负片:

    /[^\S\r\n]/
    

    也就是说,不是空白(大写的S补码),也不是回车,也不是换行。分配外部非( ,补充 ^ 在字符类)中 De Morgan's law ,这相当于空白,但不是回车或换行。包括两者 \r \n 在该模式中,正确处理所有Unix(LF)、经典Mac OS(CR)和DOS ISH(CRLF) newline conventions .

    不必相信我的话:

    #! /usr/bin/env perl
    
    use strict;
    use warnings;
    
    use 5.005;  # for qr//
    
    my $ws_not_crlf = qr/[^\S\r\n]/;
    
    for (' ', '\f', '\t', '\r', '\n') {
      my $qq = qq["$_"];
      printf "%-4s => %s\n", $qq,
        (eval $qq) =~ $ws_not_crlf ? "match" : "no match";
    }
    

    输出:

    " "  => match
    "\f" => match
    "\t" => match
    "\r" => no match
    "\n" => no match

    注意排除垂直标签,但这是 addressed in v5.18 .

    在过于严厉地反对之前,Perl文档使用相同的技术。中的脚注 “Whitespace” section of perlrecharclass 读数

    在Perlv5.18之前, \s 与垂直选项卡不匹配。 [^\S\cK] (模糊地)匹配什么 的S 传统上是这样。

    这个 same section of perlrecharclass 同时也提出了其他不会冒犯语言教师反对双重否定的方法。

    外部区域设置和Unicode规则,或者当 /a 开关有效, 的S 比赛 [\t\n\f\r ] 从Perlv5.18开始,垂直标签, \cK . 丢弃 R \n 离开 /[\t\f\cK ]/ 用于匹配空白而不是换行符。

    如果文本是Unicode,请使用与下面的子代码类似的代码从中的表构造模式。 the aforementioned documentation section .

    sub ws_not_nl {
      local($_) = <<'EOTable';
    0x0009        CHARACTER TABULATION   h s
    0x000a              LINE FEED (LF)    vs
    0x000b             LINE TABULATION    vs  [1]
    0x000c              FORM FEED (FF)    vs
    0x000d        CARRIAGE RETURN (CR)    vs
    0x0020                       SPACE   h s
    0x0085             NEXT LINE (NEL)    vs  [2]
    0x00a0              NO-BREAK SPACE   h s  [2]
    0x1680            OGHAM SPACE MARK   h s
    0x2000                     EN QUAD   h s
    0x2001                     EM QUAD   h s
    0x2002                    EN SPACE   h s
    0x2003                    EM SPACE   h s
    0x2004          THREE-PER-EM SPACE   h s
    0x2005           FOUR-PER-EM SPACE   h s
    0x2006            SIX-PER-EM SPACE   h s
    0x2007                FIGURE SPACE   h s
    0x2008           PUNCTUATION SPACE   h s
    0x2009                  THIN SPACE   h s
    0x200a                  HAIR SPACE   h s
    0x2028              LINE SEPARATOR    vs
    0x2029         PARAGRAPH SEPARATOR    vs
    0x202f       NARROW NO-BREAK SPACE   h s
    0x205f   MEDIUM MATHEMATICAL SPACE   h s
    0x3000           IDEOGRAPHIC SPACE   h s
    EOTable
    
      my $class;
      while (/^0x([0-9a-f]{4})\s+([A-Z\s]+)/mg) {
        my($hex,$name) = ($1,$2);
        next if $name =~ /\b(?:CR|NL|NEL|SEPARATOR)\b/;
        $class .= "\\N{U+$hex}";
      }
    
      qr/[$class]/u;
    }
    

    其他应用

    双重否定技巧对于匹配字母字符也很方便。记住 \w 匹配单词字符、字母字符 数字和下划线。我们这些丑陋的美国人有时想把它写成,比如,

    if (/[A-Za-z]+/) { ... }
    

    但是双重否定字符类可以尊重区域设置:

    if (/[^\W\d_]+/) { ... }
    

    用这种方式表达单词字符而不是数字或下划线有点不透明。posix字符类更直接地传达意图。

    if (/[[:alpha:]]+/) { ... }
    

    或使用Unicode属性作为 szbalint 建议

    if (/\p{Letter}+/) { ... }
    
        3
  •  42
  •   Community Egal    7 年前

    一个变异 Greg’s answer 包括回车:

    /[^\S\r\n]/
    

    这个regex比 /[^\S\n]/ 没有 \r . 我的理由是Windows使用 \r\n 用于换行,使用Mac OS 9 R . 你不太可能找到 R 没有 \n 现在,但如果你真的找到了它,它不可能意味着任何东西除了新行。因此,因为 R 可以是换行,我们也应该排除它。

        4
  •  11
  •   Aleksandr Dubinsky    5 年前

    你要找的是POSIX blank 字符类。在Perl中,它被引用为:

    [[:blank:]]
    

    在Java中(不要忘记启用) UNICODE_CHARACTER_CLASS ):

    \p{Blank}
    

    与同类产品相比 \h POSIX 空白的 由更多的regex引擎支持( reference )一个主要的好处是它的定义固定在 Annex C: Compatibility Properties of Unicode Regular Expressions 以及所有支持Unicode的regex风格的标准。(例如,在Perl中, h 选择另外包括 MONGOLIAN VOWEL SEPARATOR 然而,有利于 h 它总是检测Unicode字符(即使引擎不一致),POSIX字符类通常只默认为ASCII(如Java)。

    但问题是,即使坚持使用Unicode也不能100%解决这个问题。考虑以下字符,这些字符在Unicode中不被视为空格:

    前面提到的蒙古语元音分隔符不包括在内,这可能是一个很好的原因。它与200c和200d一起出现在words(afaik)中,因此打破了所有其他空白区都遵守的基本规则:您可以用它标记化。它们更像修饰符。然而, ZERO WIDTH SPACE , WORD JOINER ZERO WIDTH NON-BREAKING SPACE (如果它不是字节顺序标记)符合我书中的空白规则。因此,我将它们包含在水平空白字符类中。

    在Java中:

    static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
    
        5
  •  8
  •   Avinash Raj    9 年前

    下面的regex将匹配空格,但不匹配换行符。

    (?:(?!\n)\s)
    

    DEMO

    如果还想添加回车,则添加 \r | 负向前看中的运算符。

    (?:(?![\n\r])\s)
    

    DEMO

    添加 + 在非捕获组之后匹配一个或多个空白。

    (?:(?![\n\r])\s)+
    

    DEMO

    我不知道你们为什么没提到posix字符类 [[:blank:]] 与任何水平空白相匹配( 空格和制表符 )这个posix chracter类可以在bre上工作( 基本正则表达式 ) 扩展正则表达式 PCRE) Perl兼容正则表达式 )

    DEMO

        6
  •  -3
  •   Amal Murali rogal111    10 年前

    m/ /g 给我空间 / / 它会起作用的。或使用 \S 它将替换所有特殊字符,如制表符、换行符、空格等。