空格匹配正则表达式-Java


106

用于正则表达式的Java API 声明\s将匹配空格。因此,正则表达式\\s\\s应匹配两个空格。

Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);
while (matcher.find()) matcher.replaceAll(" ");

目的是用单个空格替换两个连续空格的所有实例。但是,这实际上不起作用。

我是否对正则表达式或“空白”有严重的误解?


1
字符串具有replaceAll函数,可以节省几行代码。download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
Zach L

1
这不是您的误解,而是Java。尝试分割一个字符串,如"abc \xA0 def \x85 xyz"我所见:那里只有三个字段。
tchrist 2011年

3
您是否尝试过“ \\ s +”。以此将两个或多个空格替换为一个。
hrzafer 2013年

一个多小时以来,我一直在想为什么我的\\拆分未在空格上拆分。太感谢了!
Marcin

Answers:


44

是的,您需要获取以下结果matcher.replaceAll()

String result = matcher.replaceAll(" ");
System.out.println(result);

18
加。我觉得自己是地球上最大的白痴。我和其他两个人似乎都没有注意到。我想有时候最愚蠢的小错误会让我们失望,是吗?

如此真实!我猜这是他们中最好的人发生的事情
赛伯萨拉斯(Saibharath)2014年

如果文本中有空白,我需要得到什么?
吉尔伯托·伊瓦拉

如果您要匹配unicode空格,请按照以下我的回答使用\ p {Zs}而不是\ s。
罗伯特

194

您不能\s在Java中使用它来匹配其自身的本机字符集上的空格,因为Java不支持Unicode空格属性-即使必须严格遵守Unicode空格才能满足UTS#18的RL1.2! does,它所拥有的并不是符合标准的。

Unicode将26个代码点定义为\p{White_Space}:其中20个是各种\pZ GeneralCategory = Separator,其余6个是\p{Cc} GeneralCategory = Control

空白是一个相当稳定的属性,而这些空白几乎一直存在。即使这样,Java也没有符合Unicode标准的属性,因此您必须使用如下代码:

String whitespace_chars =  ""       /* dummy empty string for homogeneity */
                        + "\\u0009" // CHARACTER TABULATION
                        + "\\u000A" // LINE FEED (LF)
                        + "\\u000B" // LINE TABULATION
                        + "\\u000C" // FORM FEED (FF)
                        + "\\u000D" // CARRIAGE RETURN (CR)
                        + "\\u0020" // SPACE
                        + "\\u0085" // NEXT LINE (NEL) 
                        + "\\u00A0" // NO-BREAK SPACE
                        + "\\u1680" // OGHAM SPACE MARK
                        + "\\u180E" // MONGOLIAN VOWEL SEPARATOR
                        + "\\u2000" // EN QUAD 
                        + "\\u2001" // EM QUAD 
                        + "\\u2002" // EN SPACE
                        + "\\u2003" // EM SPACE
                        + "\\u2004" // THREE-PER-EM SPACE
                        + "\\u2005" // FOUR-PER-EM SPACE
                        + "\\u2006" // SIX-PER-EM SPACE
                        + "\\u2007" // FIGURE SPACE
                        + "\\u2008" // PUNCTUATION SPACE
                        + "\\u2009" // THIN SPACE
                        + "\\u200A" // HAIR SPACE
                        + "\\u2028" // LINE SEPARATOR
                        + "\\u2029" // PARAGRAPH SEPARATOR
                        + "\\u202F" // NARROW NO-BREAK SPACE
                        + "\\u205F" // MEDIUM MATHEMATICAL SPACE
                        + "\\u3000" // IDEOGRAPHIC SPACE
                        ;        
/* A \s that actually works for Java’s native character set: Unicode */
String     whitespace_charclass = "["  + whitespace_chars + "]";    
/* A \S that actually works for  Java’s native character set: Unicode */
String not_whitespace_charclass = "[^" + whitespace_chars + "]";

现在,您可以whitespace_charclass + "+"在中将其用作模式replaceAll


对不起,所有这些。Java的正则表达式在它自己的本机字符集上不能很好地工作,因此您真的必须跳过各种特殊的箍圈才能使其正常工作。

如果你觉得白色空间是坏的,你应该看什么,你必须做的就是\w\b最终检点!

是的,这是可能的,是的,这是一个令人烦恼的混乱。甚至是慈善的。获得适用于Java的标准正则表达式库的最简单方法是将JNI移交给ICU。这就是Google在Android上所做的事情,因为OraSun的表现并不理想。

如果您不想这样做,但仍然想坚持使用Java,我有一个前端正则表达式重写库,我写过“修复” Java的模式,至少可以使其符合UTSRL1.2a的要求。#18,Unicode正则表达式


12
感谢您注意Java的正则表达式限制。+1
ridgerunner

4
我将这个答案投票为有帮助的,发现我已经拥有了。因此,再次感谢您:)
Andrew Wyld 2013年

5
这真的很旧。在java7中使用UNICODE_CHARACTER_CLASS标志修复此问题是否正确?(或使用(?U))
kritzikratzi 2014年

5
@tchrist如果在Java 7+中已解决此问题,您可以使用现在正确的方法来更新答案吗?
Beerbajay 2015年

7
使用Java 7+,您可以执行:“(?U)\ s”以符合Unicode技术标准的要求运行正则表达式。或者,您可以在创建模式时将UNICODE_CHARACTER_CLASS标志设置为true。这是文档:docs.oracle.com/javase/7/docs/api/java/util/regex / ...
Didier A.

15

对于Java(不是php,不是javascript,不是其他):

txt.replaceAll("\\p{javaSpaceChar}{2,}"," ")

字符串是不可变的,因此您必须将结果分配给某些内容,例如'txt = txt.replaceAll()'我没有否决您的答案,但这可能就是其他人这样做的原因。

6
我知道replaceAll返回一个字符串,重要的是4个Java程序员是\\ p {javaSpaceChar}
surfealokesea

2
最初的问题犯了一个错误,即没有将新字符串分配给变量。因此指出该错误是答案的最重要点。

这完全解决了我在Groovy中的问题!最后!我一直在尝试每一个正则表达式,我发现它会匹配所有空格,包括NON-BREAK-SPACE(ASCII 160)!
皮科

5

当我向Regexbuddy(正则表达式开发人员应用程序)论坛发送问题时,我得到了对\ s Java问题的更准确答复:

“消息作者:Jan Goyvaerts

在Java中,简写\ s,\ d和\ w仅包含ASCII字符。...这不是Java中的错误,而只是使用正则表达式时需要注意的许多事情之一。要匹配所有Unicode空格和换行符,可以在Java中使用[\ s \ p {Z}]。RegexBuddy尚不支持特定于Java的属性,例如\ p {javaSpaceChar}(与[\ s \ p {Z}]完全相同的字符)。

如果输入仅是ASCII,则\ s \ s将匹配两个空格。真正的问题在于OP的代码,正如该问题的公认答案所指出的那样。”


3
[\s\p{z}]省略Unicode“下一行”字符U + 0085。使用[\s\u0085\p{Z}]
罗伯特·图珀洛-施内克

3

似乎为我工作:

String s = "  a   b      c";
System.out.println("\""  + s.replaceAll("\\s\\s", " ") + "\"");

将打印:

" a  b   c"

我认为您打算这样做而不是代码:

Pattern whitespace = Pattern.compile("\\s\\s");
Matcher matcher = whitespace.matcher(s);
String result = "";
if (matcher.find()) {
    result = matcher.replaceAll(" ");
}

System.out.println(result);

3

为了您的目的,您可以使用以下代码段:

import org.apache.commons.lang3.StringUtils;

StringUtils.normalizeSpace(string);

这将把间距归一化为单个,也将去除起始和尾随空白。

String sampleString = "Hello    world!";
sampleString.replaceAll("\\s{2}", " "); // replaces exactly two consecutive spaces
sampleString.replaceAll("\\s{2,}", " "); // replaces two or more consecutive white spaces

1
Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);

boolean flag = true;
while(flag)
{
 //Update your original search text with the result of the replace
 modLine = matcher.replaceAll(" ");
 //reset matcher to look at this "new" text
 matcher = whitespace.matcher(modLine);
 //search again ... and if no match , set flag to false to exit, else run again
 if(!matcher.find())
 {
 flag = false;
 }
}

3
迈克,虽然我很感谢您抽出宝贵的时间回答问题,但几个月前已经解决了这个问题。无需回答这么古老的问题。

6
如果某人可以显示其他更好的解决方案,那么回答旧问题是完全合法的。
james.garriss 2015年

1

自从首次提出该问题以来,Java一直在发展。您可以使用该\p{Zs}组来匹配所有方式的unicode空格字符。

因此,如果您想用一个普通空间替换一个或多个奇异空间,则可以这样做:

String txt = "whatever my string is";
txt.replaceAll("\\p{Zs}+", " ")

另外值得一知道,如果你使用的trim()字符串函数,你应该看一看的(比较新)strip()stripLeading()以及stripTrailing()对字符串的函数。可以帮助您剪裁各种松散的空白字符。有关包含什么空间的更多信息,请参见Java Character.isWhitespace()函数。


-3

在RE中使用空格是很痛苦的,但我相信它们会起作用。还可以使用StringTokenizer或split()方法解决OP的问题。但是,要使用RE(取消注释println()以查看匹配器如何分解String),下面是示例代码:

import java.util.regex.*;

public class Two21WS {
    private String  str = "";
    private Pattern pattern = Pattern.compile ("\\s{2,}");  // multiple spaces

    public Two21WS (String s) {
            StringBuffer sb = new StringBuffer();
            Matcher matcher = pattern.matcher (s);
            int startNext = 0;
            while (matcher.find (startNext)) {
                    if (startNext == 0)
                            sb.append (s.substring (0, matcher.start()));
                    else
                            sb.append (s.substring (startNext, matcher.start()));
                    sb.append (" ");
                    startNext = matcher.end();
                    //System.out.println ("Start, end = " + matcher.start()+", "+matcher.end() +
                    //                      ", sb: \"" + sb.toString() + "\"");
            }
            sb.append (s.substring (startNext));
            str = sb.toString();
    }

    public String toString () {
            return str;
    }

    public static void main (String[] args) {
            String tester = " a    b      cdef     gh  ij   kl";
            System.out.println ("Initial: \"" + tester + "\"");
            System.out.println ("Two21WS: \"" + new Two21WS(tester) + "\"");
}}

它产生以下内容(使用javac编译并在命令提示符下运行):

%java Two21WS初始:“ ab cdef gh ij kl” Two21WS:“ ab cdef gh ij kl”


8
WTF !!当您只能打电话时,为什么要做所有这些replaceAll()呢?
艾伦·摩尔
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.