重複する単語の正規表現


114

私は正規表現の初心者です。次のような重複する連続する単語と「一致する」単一の正規表現を作成する方法を理解できません。

パリ春。

それは関連しているわけはありません。

なぜ笑っている?ある私の私の正規表現は、THAT悪いです?

上記のすべての太字の文字列に一致する単一の正規表現はありますか?


4
@poly:これは「非難」ではありませんでしたが、答えとして「いいえ」を完全に取ることができる穏やかで通常の質問でした。@ジョシュア:はい、一部の人々(少なからず)がこのサイトに宿題を任せています。しかし、宿題をすることは、タグが付けられているので、SOで行うことは悪いことではありません。通常、答えのスタイルは「ここが解決策です」から「ここは考えたことのないものがあります」に変わりますが、それは良いことです。誰かが区別を試み続けなければなりません。彼の場合、それは私でした、そして他の場所で「他の人々」は同じことをします。それで全部です。
Tomalak、

13
「これは職場の質問のように聞こえますか?」のような質問を決して見たくないと思います。そして人々はスタックオーバーフローが誰かの仕事をしているのかどうか議論するでしょう。
marcio 14

@Joshua +1、あなたが受け入れた正規表現ソリューションに関して、マッチ(重複)をペアの1つの要素(たとえばnot that that is related-> not that is related)で置き換える方法を教えてください。よろしくお願いします
Antoine

@ジョシュア私は解決策を見つけたと思います:私は置き換える必要があり\1ます!
Antoine

2
@DavidLealどう\b(\w+)\s+(\1\s*)+\bですか?
ytu 2018年

回答:


141

次の正規表現を試してください:

\b(\w+)\s+\1\b

これ\bは単語の境界\1であり、最初のグループのキャプチャされた一致を参照します。


1
不思議に思う; それも可能\0ですか?(\0現在のポイントまでの正規表現全体、または\0正規表現全体を指します)
Pindatjuh 2010年

@Pindatjuh:いいえ、そのサブマッチもマッチ全体の一部になるので、そうは思わない。
ガンボ

少なくとも、Eclipseの検索/置換ダイアログで使用される正規表現エンジンで動作します。
Chaos_99 2013年

3
ただの警告ですが、これはアポストロフィや(ノエルが言及しているように)ハイフンを含む単語を処理しません。Mikeのソリューションはこれらのケースでより適切に機能します

3
さらに、それは3つ(またはそれ以上)をキャッチしません。dup/ triplicateの1つが文字列の最後にある場合はそうではありません
Nico

20

私はこの正規表現がより多くの状況を処理すると信じています:

/(\b\S+\b)\s+\b\1\b/

テスト文字列の良い選択はここで見つけることができます:http : //callumacrae.github.com/regex-tuesday/challenge1.html


すばらしい、アポストロフィ/ハイフンなどで機能します。あまりにも-ありがとう!

challenge1リンクで、グループ化された単語を使用するために置換領域に何を配置しますか?試した<strong>\0</strong>が動作しなかった。
uptownhr 2016

2
3つ(またはそれ以上)はキャッチされません。dup/ triplicateの1つが文字列の最後にある場合はキャッチされません
Nico

@uptownhr使いたい$1 <strong>$2</strong>。ただし、別の正規表現も使用してください/\b(\S+) (\1)\b/gi。ここにリンクは次のとおりです。callumacrae.github.io/regex-tuesday/...
dsalaj

また、<p class="bebe">bla bla</p>この正規表現の式をどのように統合できるかなど、特定のタグからすべての連続する単語を検索する場合はどうすればよいですか。
Just Me

7

以下のREでこれを試してください

  • \ b単語の始まり単語の境界
  • \ W +任意の単語文字
  • \ 1同じ単語がすでに一致しています
  • \ b単語の終わり
  • ()*繰り返し

    public static void main(String[] args) {
    
        String regex = "\\b(\\w+)(\\b\\W+\\b\\1\\b)*";//  "/* Write a RegEx matching repeated words here. */";
        Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE/* Insert the correct Pattern flag here.*/);
    
        Scanner in = new Scanner(System.in);
    
        int numSentences = Integer.parseInt(in.nextLine());
    
        while (numSentences-- > 0) {
            String input = in.nextLine();
    
            Matcher m = p.matcher(input);
    
            // Check for subsequences of input that match the compiled pattern
            while (m.find()) {
                input = input.replaceAll(m.group(0),m.group(1));
            }
    
            // Prints the modified sentence.
            System.out.println(input);
        }
    
        in.close();
    }

5

広く使用されているPCREライブラリは、このような状況を処理できます(ただし、POSIX準拠の正規表現エンジンで同じことを実現できません)。

(\b\w+\b)\W+\1

のように、2つの単語の文字を一致させるものが必要です\W+\bそれはどんな文字も消費しないのでそれをしません。
アランムーア

これにより、などの場合に誤検出マッチングが発生する可能性があります... the these problems...。このソリューションは、単語の境界を十分に実装するガンボのパターンの一般的な構造ほど信頼できません。
mickmackusa

また、<p class="bebe">bla bla</p>この正規表現の式をどのように統合できるかなど、特定のタグからすべての連続する単語を検索する場合はどうすればよいですか。
Just Me

4

これは、twitchボットで重複したフレーズを削除するために使用する正規表現です。

(\S+\s*)\1{2,}

(\S+\s*) 空白ではなく空白に続いていない文字列を探します。

\1{2,}次に、一致する文字列でそのフレーズの2つ以上のインスタンスを探します。同一のフレーズが3つある場合、一致します。


この答えは誤解を招くものです。重複は検索しません。3回以上出現する部分文字列を検索します。また\s*、キャプチャグループ内にあるため、それほど堅牢ではありません。このデモをご覧ください:regex101.com/r/JtCdd6/1
mickmackusa

さらに、極端なケース(低頻度のテキスト)は、誤検出の一致を生成します。例えばI said "oioioi" that's some wicked mistressship!oioioisss
mickmackusa

4

次の式は、任意の数の連続する単語を見つけるために正しく機能するはずです。照合では大文字と小文字が区別されません。

String regex = "\\b(\\w+)(\\s+\\1\\b)*";
Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher(input);

// Check for subsequences of input that match the compiled pattern
while (m.find()) {
     input = input.replaceAll(m.group(0), m.group(1));
}

入力例:Goodbye goodbye GooDbYe

出力例:さようなら

説明:

正規表現:

\ b:単語境界の始まり

\ w +:任意の数の単語文字

(\ s + \ 1 \ b)*:前の単語と一致し、単語の境界を終了する単語が続く任意の数のスペース。*で囲まれた全体は、複数の繰り返しを見つけるのに役立ちます。

グループ化:

m.group(0):上記のケースで一致したグループを含める必要がありますGoodbye goodbye GooDbYe

m.group(1):上記のケースでは、一致したパターンの最初の単語が含まれます。

Replaceメソッドは、連続するすべての一致する単語をその単語の最初のインスタンスで置き換えます。


3

いいえ、それは不規則な文法です。使用できるエンジン/言語固有の正規表現があるかもしれませんが、それを行うことができる普遍的な正規表現はありません。


12
厳密な意味では正しいのですが、グループ化や後方参照をサポートしていない、真剣に使用されている正規表現エンジンはもう存在しないと思います。
Tomalak

3

これは、複数の単語を複数回キャッチするものです。

(\b\w+\b)(\s+\1)+

また、<p class="bebe">bla bla</p>この正規表現の式をどのように統合できるかなど、特定のタグからすべての連続する単語を検索する場合はどうすればよいですか。
Just Me

HTML解析が必要になると思います。検索する特定のタグについて、HTML内のすべてのタグの出現を検索し、この正規表現を1つずつ実行します。または、HTMLのどこで繰り返しが発生するかを気にしない場合は、すべてのタグテキスト属性を連結し、連結された文字列に対して正規表現を実行します
synaptikon

私は自分自身が答えを見つける<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

正規表現からストリップ2+の重複する単語(連続する単語または連続しない単語)

2つ以上の重複する単語をキャッチし、1つの単語だけを残すことができるこの正規表現を試してください。また、重複する単語は連続している必要はありません

/\b(\w+)\b(?=.*?\b\1\b)/ig

ここで\bは、ワード境界に?=使用され、ポジティブルックアヘッドに\1使用され、逆参照に使用されます。

ソースの


1
連続しないのは悪い考えです:"the cat sat on the mat"->" cat sat on the mat"
Walf

@Walf True。それにもかかわらず、これが意図されているシナリオがあります。(例:データをこすりながら)
Niket Pathak

私が修正したなぜあなたは再びあなたの正規表現壊しましか?私がその意図を変えたと思いましたか?リンクした例でも間違いはありません。
ウォルフ2018

うん、それは間違いだった、コピーが間違ったものを貼り付けた。実際に私の例からのものをコピーすることを意図しました。とにかく、今はうまくいきます!とてもいい!ありがとう!
Niket Pathak 2018

2

Javascriptの例:Good Partsはこれを行うように調整できます。

var doubled_words = /([A-Za-z\u00C0-\u1FFF\u2800-\uFFFD]+)\s+\1(?:\s|$)/gi;

\ bは単語の境界に\ wを使用します。\ wは[0-9A-Z_a-z]と同等です。その制限を気にしない場合は、受け入れられた答えで結構です。


2

一部の開発者は、重複する連続する空白以外の部分文字列を排除するだけでなく、3つ以上の重複を排除するソリューションを求めてこのページにアクセスしているため、適応パターンを示します。

パターン:/(\b\S+)(?:\s+\1\b)+/柄デモ
置き換えます$1(キャプチャグループ#1とfullstring試合を置き換え)

このパターンは、「空白」の非空白部分文字列に貪欲に一致し、1つ以上の空白文字(スペース、タブ、改行など)で区切られた一致した部分文字列の1つ以上のコピーが必要です。

具体的には:

  • \b (単語の境界)文字は、部分的な単語が一致しないようにするために不可欠です。
  • 2番目の括弧は非キャプチャグループです。この可変幅のサブストリングはキャプチャする必要がないため、一致/吸収されるだけです。
  • +非キャプチャグループに(一つ以上の数量詞)がより適切である*ため*、キャプチャに正規表現エンジンを「わざわざ」と出現シングルトン置き換えられます-これは無駄なパターン設計です。

*句読点を含む文や入力文字列を扱う場合は、パターンをさらに調整する必要があります。


@AdamJonesはこのパターンをphpプロジェクトで使用します。ニコの答えにはいくつかの不必要な構文があります。
mickmackusa

1

この式(上記のMikeからインスピレーションを得たもの)は、文字列の最後にあるものを含め、すべての重複、3重などをキャッチしているようですが、他のほとんどの式はこれを行いません。

/(^|\s+)(\S+)(($|\s+)\2)+/g, "$1$2")

重複を照合するように求められる質問を知っていますのみが、3つは隣同士の重複2つだけです:)

まず、(^|\s+)完全な単語で始まることを確認します。そうでない場合、「子供のステーキ」は「子供のステーキ」に行きます(「s」は一致します)。次に、すべての完全な単語((\b\S+\b))に一致し、その後に文字列の終わり($)またはいくつかのスペース(\s+ます。全体が2回以上繰り返されます。

私はこのようにしてみましたが、うまくいきました:

var s = "here here here     here is ahi-ahi ahi-ahi ahi-ahi joe's joe's joe's joe's joe's the result result     result";
print( s.replace( /(\b\S+\b)(($|\s+)\1)+/g, "$1"))         
--> here is ahi-ahi joe's the result

これをPHPに書き換えるのに問題があります。重複/三重反復などのそれぞれの出現を置き換える、一致した重複の単一のコピーを取得することが重要です。これまでのところ、preg_replace( '/(^ | \ s +)(\ S +)( ($ | \ s +)\ 2)+ / im '、' $ 0 '、$ string);
AdamJones 2017

これが最良の答えです。\b最後に次のように追加することで、/(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")これを微調整しました。これは、次のような状況で機能します。the the string String string stringing the the along the the stringthe string stringing the along the stringNoticeになりstring stringingます。それはあなたの答えと一致します。ありがとうございました。
サント

-1

重複する単語の大文字と小文字を区別しないチェックが必要な場合に使用します。

(?i)\\b(\\w+)\\s+\\1\\b

大文字と小文字を区別しないパターン修飾子を使用しても、パターンには使用できません。フラグが影響する文字範囲はありません。
mickmackusa

これは事実上、受け入れられた回答の複製であり、ページに値を追加しません。ページの膨張を減らすために、この回答を削除することを検討してください。
mickmackusa
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.