ホワイトスペースマッチング正規表現-Java


106

正規表現用のJava APIは、\s空白に一致すると述べています。したがって、正規表現\\s\\sは2つのスペースに一致する必要があります。

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

この目的は、2つの連続する空白のすべてのインスタンスを1つのスペースに置き換えることです。ただし、これは実際には機能しません。

正規表現または「ホワイトスペース」という用語について重大な誤解がありますか?


1
Stringには、数行のコードを節約するreplaceAll関数があります。download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
Zach L

1
それはあなたの誤解ではありませんが、Javaの誤解です。次のよう"abc \xA0 def \x85 xyz"に文字列を分割してみてください。つまり、フィールドは3つしかありません。
tchrist

3
「\\ s +」を試してみましたか?これで、2つ以上のスペースを1つに置き換えます。
hrzafer 2013

私の\\ s分割が空白で分割されない理由を1時間以上疑問に思っていました。どうもありがとう!
Marcin 2014年

回答:


44

ええ、あなたはの結果をつかむ必要がありますmatcher.replaceAll()

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

18
ああ。私は地球上で最大の馬鹿のように感じます。私も他の2人もそれに気づかなかったようです。愚かな小さなエラーが時々私たちを捨ててしまうと思いますか?

仰るとおり!それは彼らの最高のもので起こると思います
サイバラト2014

テキストに空白が含まれている場合、取得する必要がある場合はどうなりますか?
Gilberto Ibarra

ユニコードの空白と一致させたい場合は、以下の私の回答に従って、\ sの代わりに\ p {Zs}を使用してください。
ロバート

194

\sJavaは、独自のネイティブ文字セットの空白と一致させるために使用できません。これは、JavaがUnicodeの空白のプロパティをサポートしていないためです。 それが持っているものは、残念ながら標準に準拠していません。

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のものに置き換えることです。OraSunは対応していません。

あなたがそれをしたくないがそれでもJavaを使いたい場合は、少なくともUTSRL1.2aの要件に準拠させるためにJavaのパターンを「修正」するために書いたフロントエンドの正規表現書き換えライブラリがあります#18、Unicode正規表現


12
Javaの正規表現の制限について頭を上げてくれてありがとう。+1
リッジランナー2011

4
私はこの回答を役に立ったと投票して、すでに持っていたことがわかりました。だから、ありがとうの時間を:)
アンドリューWyld

5
これは本当に古いです。これはjava7でUNICODE_CHARACTER_CLASSフラグを使用して修正されたことは正しいですか?(または(?U)を使用)
kritzikratzi 14

5
@tchristこれがJava 7+で修正されている場合、これを行うための正しい方法で答えを更新できますか?
beerbajay

7
Java 7以降では、 "(?U)\ s"を実行して、Unicode技術標準に準拠した正規表現を実行できます。または、パターンを作成するときにUNICODE_CHARACTER_CLASSフラグをtrueにすることができます。ここではドキュメントがあります:docs.oracle.com/javase/7/docs/api/java/util/regex/...
ディディエA.

15

Java(php、javascript、その他)の場合:

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

文字列は不変なので、結果を「txt = txt.replaceAll()」などの何かに割り当てる必要があります。私はあなたの回答に投票しませんでしたが、それが誰かがそうした理由かもしれません。
2013年

6
replaceAllが文字列を返すことは知っています。4つのJavaプログラマが重要なことです。\\ p {javaSpaceChar}
surfealokesea

2
元の質問では、新しい文字列を変数に割り当てないという誤りがありました。したがって、その間違いを指摘することが答えの最も重要なポイントです。
2013年

これでGroovyでの私の問題は完全に解決しました!最後に!NON-BREAK-SPACE(ASCII 160)を含むすべての空白に一致することがわかったすべての正規表現を試しました!!!
ピコ

5

Regexbuddy(regex開発者アプリケーション)フォーラムに質問を送信すると、Javaの質問に対してより正確な回答が得られました。

「メッセージ作成者:Jan Goyvaerts

Javaでは、省略形の\ s、\ d、および\ wにはASCII文字のみが含まれます。...これはJavaのバグではありませんが、正規表現を操作するときに注意する必要がある多くのことの1つにすぎません。すべてのUnicode空白と改行を一致させるには、Javaで[\ s \ p {Z}]を使用できます。RegexBuddyは、\ p {javaSpaceChar}([\ s \ p {Z}]とまったく同じ文字に一致する)などのJava固有のプロパティをまだサポートしていません。

...入力がASCIIのみの場合、\ s \ sは2つのスペースに一致します。本当の問題はOPのコードにあり、その質問で受け入れられた回答で指摘されています。」


3
[\s\p{z}]Unicode "次の行"文字U + 0085を省略します。を使用し[\s\u0085\p{Z}]ます。
Robert Tupelo-Schneck 2015

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);

これにより、間隔が1つに正規化され、開始と終了の空白も削除されます。

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スペース文字を照合できます。

したがって、1つ以上のエキゾチックなスペースをプレーンなスペースに置き換える場合は、次のようにします。

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

また知っておく価値、あなたが使用した場合trim()、あなたは(比較的新しい)を見てみる必要がある文字列関数をstrip()stripLeading()と、stripTrailing()文字列の機能。を使用すると、あらゆる種類の空白文字を切り取ることができます。含まれるスペースの詳細については、JavaのCharacter.isWhitespace()関数を参照してください。


-3

REでの空白の使用は苦痛ですが、私はそれらがうまくいくと信じています。OPの問題は、StringTokenizerまたはsplit()メソッドを使用して解決することもできます。ただし、REを使用するには(println()のコメントを外して、マッチャーが文字列を分割している方法を確認します)、サンプルコードを次に示します。

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 Initial: "ab cdef gh ij kl" Two21WS: "ab cdef gh ij kl"


8
WTF !? replaceAll()代わりに電話をかけることができるのに、なぜそんなことをすべてしたいのですか?
アランムーア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.