我有时想匹配空白,而不是换行符。
到目前为止,我一直在使用[\t]。有不那么尴尬的方式吗?
我有时想匹配空白,而不是换行符。
到目前为止,我一直在使用[\t]。有不那么尴尬的方式吗?
使用双重否定:
/[^\S\r\n]/
也就是说,非空格符(大写S作为补充)或非回车符或非换行符。根据De Morgan定律分配外部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}+/) { ... }
Greg的答案也包含了回车:
/[^\S\r\n]/
这个正则表达式比没有\r的/[^\S\n]/更安全。我的理由是Windows使用\r\n作为换行符,而Mac OS 9使用\r。现在你不太可能找到不带\n的\r,但如果你确实找到了,它只能表示换行符。因此,既然\r可以表示换行符,我们也应该排除它。
您要寻找的是POSIX空白字符类。在Perl中,它被引用为:
[[:blank:]]
在Java中(不要忘记启用UNICODE_CHARACTER_CLASS):
\p{Blank}
Compared to the similar \h, POSIX blank is supported by a few more regex engines (reference). A major benefit is that its definition is fixed in Annex C: Compatibility Properties of Unicode Regular Expressions and standard across all regex flavors that support Unicode. (In Perl, for example, \h chooses to additionally include the MONGOLIAN VOWEL SEPARATOR.) However, an argument in favor of \h is that it always detects Unicode characters (even if the engines don't agree on which), while POSIX character classes are often by default ASCII-only (as in Java).
但问题是,即使坚持使用Unicode也不能100%解决问题。考虑以下字符,它们在Unicode中不被视为空格:
U+ 180e蒙古语元音分隔符 U+ 200b零宽空间 U+ 200c零宽度非细木工 U+ 200d零宽细木工 U+2060字木工 U+ feff零宽度不间断空间 摘自https://en.wikipedia.org/wiki/White-space_character
The aforementioned Mongolian vowel separator isn't included for what is probably a good reason. It, along with 200C and 200D, occur within words (AFAIK), and therefore breaks the cardinal rule that all other whitespace obeys: you can tokenize with it. They're more like modifiers. However, ZERO WIDTH SPACE, WORD JOINER, and ZERO WIDTH NON-BREAKING SPACE (if it used as other than a byte-order mark) fit the whitespace rule in my book. Therefore, I include them in my horizontal whitespace character class.
在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匹配。匹配23个字符
所有的空白字符要么是垂直的,要么是水平的,没有重叠,但它们不是合适的子集,因为\h也匹配U+00A0 no - break SPACE, \v也匹配U+0085 NEXT LINE,它们都不被\s匹配