匹配空格但不匹配换行符

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

到目前为止,我一直在使用[ \t]。有不那么尴尬的方式吗?

193781 次浏览

使用双重否定:

/[^\S\r\n]/

也就是说,非空格符(大写S作为补充)或非回车符或非换行符。将外部not (即。,字符类中的补充^)与德摩根定律分布,这相当于“空白但不是回车或换行符”。在模式中包含\r\n可以正确处理所有Unix (LF)、经典Mac OS (CR)和DOS-ish (CR LF) 换行符的约定

没必要相信我的话:

#! /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

注意排除了垂直制表符,但这是在v5.18中解决

在强烈反对之前,Perl文档使用了相同的技术。perlrecharclass的“Whitespace”部分中的脚注为

在Perl v5.18之前,\s不匹配垂直选项卡。[^\S\cK](模糊地)匹配\s的传统功能。

perlrecharclass的同一部分还建议了其他不会冒犯语言教师反对双重否定的方法。

在区域设置和Unicode规则之外,或者当/a开关生效时,“\s匹配[\t\n\f\r ],并且从Perl v5.18开始,垂直选项卡\cK。”丢弃\r\n,留下/[\t\f\cK ]/用于匹配空格,而不是换行符。

如果你的文本是Unicode,使用类似于下面的子代码从前面提到的文档部分中的表中构造一个模式。

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:]]+/) { ... }

或者使用szbalint建议的Unicode属性

if (/\p{Letter}+/) { ... }

格雷格的回答的一个变体,它也包含回车:

/[^\S\r\n]/

这个正则表达式比没有\r/[^\S\n]/更安全。我的推理是Windows使用\r\n作为换行符,而Mac OS 9使用\r。现在你不太可能在没有\n的情况下找到\r,但如果你找到了它,它只能意味着一个换行符。因此,由于\r可以表示换行符,我们也应该排除它。

m/ /g只是在/ /中留出空间,它可以工作。或者使用\S -它将替换所有特殊字符,如制表符、换行符、空格等等。

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

[[:blank:]]

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

\p{Blank}

与类似的\h相比,POSIX blank被更多的正则引擎(参考)支持。一个主要的好处是它的定义在附录C: Unicode正则表达式的兼容性属性中是固定的,并且是支持Unicode的所有regex风格的标准。(例如,在Perl中,\h选择额外包括MONGOLIAN VOWEL SEPARATOR。)然而,支持\h的一个论点是,它总是检测Unicode字符(即使引擎不同意),而POSIX字符类通常默认为仅ascii(就像在Java中一样)。

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

前面提到的蒙古元音分隔符没有包括在内,这可能是一个很好的理由。它与200C和200D一起出现在单词中(AFAIK),因此打破了所有其他空格所遵循的基本规则:您可以使用它进行标记。它们更像是修饰语。然而,ZERO WIDTH SPACEWORD JOINERZERO WIDTH NON-BREAKING SPACE(如果它被用作字节顺序标记之外的符号)符合我书中的空白规则。因此,我将它们包含在水平空白字符类中。

在Java中:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"

下面的正则表达式将匹配空格,但不匹配新行字符。

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

DEMO

如果你想添加回车符,那么在负前向中添加带有|操作符的\r

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

DEMO

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

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

DEMO

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

DEMO

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

有7个垂直空格字符与\v匹配,18个水平空格字符与\h匹配。\s匹配23个字符

所有空白字符都是垂直水平,没有重叠,但它们不是合适的子集,因为\h也匹配U+00A0无间断空格,并且\v也匹配U+0085 NEXT LINE,它们都不能被\s匹配

将下面的正则表达式放在找到部分,并从“搜索模式”中选择正则表达式:

[^\S\r\n]+