匹配空格但不换行


277

有时我想匹配空格,但不匹配换行符。

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


4
顺便说一句,这些字符也是“空白”:[\r\f]
尤金·雅玛什

2
@eugeney有人还在做换页吗?(\ f's)
Aran Mulholland

1
@AranMulholland:拥有面向字符的打印机的任何人。大多数打印机具有字符模式以及PostScript或任何被称为Hewlett Packard界面的功能,并且要发送页面,您可以发送换页。
Borodin

1
@Borodin Hewlett Packard的称为PCL(打印机控制语言)。
CB_Ron

Answers:


182

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十八个水平空白字符\h\s匹配二十三个字符

所有空格字符都是垂直水平的,没有重叠,但是它们不是正确的子集,因为它们\h也匹配U + 00A0 NO-BREAK SPACE,\v还匹配U + 0085 NEXT LINE,两者都不匹配\s


7
\h仅适用于支持的语言PCRE
Avinash Raj

14
@AvinashRaj:这个问题是关于Perl的,它当然支持PCRE
Borodin

2
@AvinashRaj:除非[[:blank:]]没有不间断的空间-  "\xA0"
Borodin

6
我想说这\h对我的用例非常有效,该用例是在Notepad ++中对1个或多个连续的非换行空间进行查找/替换。没有其他(简单的)工作。
squidbe 2015年

8
使Perl \h稍微不符合标准的原因是它包含MONGOLIAN VOWEL SEPARATOR。Unicode不将其视为空格。因此,Perl \h与POSIX blank[[:blank:]]在Perl \p{Blank}中为Java)和Java 8不同\h。诚然,这是一个边缘案例。
Aleksandr Dubinsky

362

使用双负数:

/[^\S\r\n]/

即,非空白(大写的S补充)或非回车或非换行符。用De Morgan的定律分配外部非字符(^字符类中的补语),等效于“空白,但不包括回车符或换行符”。在模式中同时包含和都可以正确处理所有Unix(LF),经典Mac OS(CR)和DOS-ish(CR LF)换行符约定\r\n

无需相信我的话:

#! /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";
}

输出:

“” =>符合
“ \ f” =>匹配
“ \ t” =>匹配
“ \ r” =>没有匹配项
“ \ n” =>不匹配

请注意,垂直制表符已排除在外,但v5.18中解决

在反对之前,Perl文档使用了相同的技术。perlrecharclass“空白”部分的脚注如下:

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

4
聪明,但是这种举动是非常令人惊讶的,而且我不认为它有多么尴尬。
Qwertie 2010年

7
@Qwertie:令人惊讶的是什么?比什么还尴尬?
2010年

9
太糟糕了。

9
这是非常好的。根据要求,您匹配空白(不只是一些空白字符),并且排除了换行符。您的解决方案并不关心以下问题:“存在什么空白字符”,因为它不应该这样。这正是我想要的。(正如@Rory指出的,“换行”也可以包括\r,例如,在Windows上,所以考虑exluding那些比赛还有:/[^\S\r\n]/
蒂莫

1
这肯定会满足OP以及几乎所有搜索此问题的其他人(无论如何,都是讲英语的人)的需求。但这仍然是一个错误的答案。只要\h有可用的解决方案,就没有任何借口。
艾伦·摩尔

49

Greg答案的一种变体,也包括回车符:

/[^\S\r\n]/

这个正则表达式比/[^\S\n]/没有正则表达式更安全\r。我的理由是Windows \r\n用于换行,而Mac OS 9用于\r。如果\r没有\n今天,您将很难找到它,但是如果您找到它,那么它除了换行符之外什么也没有。因此,由于\r可以表示换行符,因此我们也应该排除它。


1
+1 Greg的解决方案最终破坏了我的文字,您的文字正常。
Timo Huovinen 2014年

您可能会惊讶于有多少程序仍然使用“ \ r”作为行尾。有时我花了一段时间才弄清楚我的问题是文件使用了这些文件。还是它使用了MacRoman字符编码...
mivk

2
看起来@Greg首先是“错误”更改了它,并且没有给您信用。这就是为什么我在这里发表评论。
安德烈·埃里科

14

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

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

演示

如果你想添加回车也再加入\r|负前瞻内部操作者。

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

演示

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

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

演示

我不知道您为什么没有提到[[:blank:]]与任何水平空白(空格和制表符)匹配的POSIX字符类。该POSIX chracter类适用于BRE(基本正则表达式),ERE(扩展正则表达式),PCRE(与Perl兼容的正则表达式))。

演示


这是最好的解决方案!
loretoparisi

13

您正在寻找的是POSIX blank字符类。在Perl中,它称为:

[[:blank:]]

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

\p{Blank}

与同类产品相比\h,POSIX blank受更多的正则表达式引擎(参考)的支持。一个主要的好处是它的定义在附件C:Unicode正则表达式的兼容性属性和所有支持Unicode的正则表达式版本中的标准中得到了固定。(例如,在Perl中,\h选择选择另外包含MONGOLIAN VOWEL SEPARATOR。。)但是,一个值得支持的论点\h是,它总是检测Unicode字符(即使引擎不同意也是如此),而POSIX字符类通常默认为ASCII -only(如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]"

您需要向Java编译中添加适当的regexp编译标志,并运行Java 7或更高版本。无论如何,问题根本不是关于Java或PCRE的,因此这无关紧要。
tchrist

@tchrist感谢您指出这一点。我将更新我的答案。但是,我不同意我的回答无关紧要。不重要的是perl原始问题中的标签。
Aleksandr Dubinsky 2014年

1
@AleksandrDubinsky,\ p {Blank}在JavaScript中不受支持,因此绝对不是“所有正则表达式口味的标准” -1
Valentin Vasilyev 2015年

最翔实。我感到不安的是,不存在一个通用且完整的“水平空白”速记字符类,并且[\p{Blank}\u200b\u180e]需要类似的恐怖。诚然,将元音分隔符视为空格字符是有道理的,但是为什么零宽度空格不在诸如\s和等类中\p{Blank},这使我不胜其烦。
Timo

后续行动:我读到两者都被认为是“边界中立的”,尽管这并不能解释为什么
蒂莫(Timo)2015年

-4

m/ /g只需在中留出空间/ /,它将起作用。或使用\S-它将替换所有特殊字符,例如tab,换行符,空格等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.