私は10文字のすべての単語を表示する正規表現を作成しようとしていますが、どの文字も繰り返されていません。
これまでのところ、私は持っています
grep --colour -Eow '(\w{10})'
これは、質問の最初の部分です。「一意性」を確認するにはどうすればよいですか?後方参照を使用する必要があることを除けば、本当に手がかりはありません。
私は10文字のすべての単語を表示する正規表現を作成しようとしていますが、どの文字も繰り返されていません。
これまでのところ、私は持っています
grep --colour -Eow '(\w{10})'
これは、質問の最初の部分です。「一意性」を確認するにはどうすればよいですか?後方参照を使用する必要があることを除けば、本当に手がかりはありません。
回答:
grep -Eow '\w{10}' | grep -v '\(.\).*\1'
2つの同一の文字を持つ単語を除外します。
grep -Eow '\w{10}' | grep -v '\(.\)\1'
繰り返し文字を含むものを除外します。
POSIXly:
tr -cs '[:alnum:]_' '[\n*]' |
grep -xE '.{10}' |
grep -v '\(.\).*\1'
tr
単語s以外の文字(c英数字とアンダースコアの組み合わせ)の配列を改行文字に変換することにより、単語を独自の行に配置します。
または1つgrep
:
tr -cs '[:alnum:]_' '[\n*]' |
grep -ve '^.\{0,9\}$' -e '.\{11\}' -e '\(.\).*\1'
(10文字未満および10文字を超える行、および文字が少なくとも2回現れる行を除外します)。
1 grep
つのみ(PCREサポート付きGNU grepまたはpcregrep
):
grep -Po '\b(?:(\w)(?!\w*\1)){10}\b'
つまり、単語境界(\b
)の後に10個の単語文字のシーケンスが続きます(各単語の後に、負の先読みPCRE演算子を使用した単語文字とそのシーケンスが続かない場合(?!...)
)。
多くの正規表現エンジンが繰り返し部分内の後方参照で動作しないため、ここで動作することは幸運です。
(少なくとも私のバージョンのGNU grepでは)
grep -Pow '(?:(\w)(?!\w*\1)){10}'
動作しませんが、
grep -Pow '(?:(\w)(?!\w*\2)){10}'
echo aa | grep -Pw '(.)\2'
バグのように聞こえる(as )
あなたがしたいことがあります:
grep -Po '(*UCP)\b(?:(\w)(?!\w*\1)){10}\b'
ASCII文字以外のロケールのASCII文字だけでなく、文字を単語コンポーネントと見なしたい、\w
または\b
考慮したい場合。
別の選択肢:
grep -Po '\b(?!\w*(\w)\w*\1)\w{10}\b'
これは、10個の単語文字が続く単語境界(単語文字のシーケンスの1つが繰り返される文字列が後に続かない単語境界)です。
おそらく心の奥にあるもの:
Babylonish
、たとえば、小文字と大文字が2つずつある場合でもすべての文字が異なるため、一致しますB
(これ-i
を変更するために使用します)。-w
、\w
そして\b
、言葉は文字(ASCIIのもののみGNUのためにあるgrep
今のところ、[:alpha:]
あなたのロケールで文字クラスが使用している場合-P
と(*UCP)
)、小数点以下の桁またはアンダースコアが。c'est
(フランス語の単語の定義によると2つの単語)またはit's
(英語の単語の定義によると1つの単語)または(フランス語の単語の定義によるrendez-vous
と1つの単語)は1つの単語とは見なされません。(*UCP)
、Unicode結合文字は単語コンポーネントと見なされないため、téléphone
($'t\u00e9le\u0301phone'
)は10文字と見なされ、そのうちの1つは非アルファ文字です。défavorisé
($'d\u00e9favorise\u0301'
)は2つé
あるにもかかわらず一致します。これは、すべての異なるアルファ文字とそれに続く鋭いアクセント(非アルファなので、e
との間に単語境界があるため)があるためです。\w
一致しません-
。
さて... 5文字の文字列の扱いにくい方法は次のとおりです。
grep -P '^(.)(?!\1)(.)(?!\1|\2)(.)(?!\1|\2|\3)(.)(?!\1|\2|\3|\4).$'
文字クラス(たとえば[^\1|\2]
)に後方参照を配置できないため、負の先読み -を使用する必要があります(?!foo)
。これはPCRE機能なので、-P
スイッチが必要です。
もちろん、10文字の文字列のパターンはかなり長くなりますが、先読みで可変長( '。*')に一致する可変長を使用するより短い方法があります。
grep -P '^(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!.*\4)(.)(?!.*\5).$'
Stephane Chazelasの啓発的な答えを読んだ後、grepの-v
スイッチを介して使用できるこれに類似した単純なパターンがあることに気付きました。
(.).*\1
チェックは一度に1文字ずつ行われるため、指定された文字の後にゼロ個以上の文字(.*
)が続き、後方参照が一致するかどうかが確認されます。 このパターンに一致しない-v
ものだけを印刷して反転します。これにより、後方参照は文字クラスで無効にできないため、より便利になります。
grep -v '\(.\).*\1'
一意の文字で任意の長さの文字列を識別するために動作しますが、
grep -P '(.)(?!.*\1)'
それは(例えば独特の文字で何でも接尾辞と一致しますから、しませんabcabc
ので、の試合をabc
最後に、とaaaa
理由をa
-したがって、最後に任意の文字列)。これは、ゼロ幅であるルックアラウンド(それらは何も消費しない)によって引き起こされる複雑さです。
(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!\4).
正規表現ですべてを実行する必要がない場合は、2つのステップで実行します。最初にすべての10文字の単語を照合し、次に一意性のためにそれらをフィルタリングします。私がこれを行う方法を知っている最短の方法は、Perlの場合です。
perl -nle 'MATCH:while(/\W(\w{10})\W/g){
undef %seen;
for(split//,$1){next MATCH if ++$seen{$_} > 1}
print
}' your_file
追加の\W
アンカーに注意して、正確に10文字の単語のみが一致するようにします。
他の人は、これは実際には規則的ではない特定の正規表現システムへのさまざまな拡張なしでは不可能だと示唆しています。ただし、一致させる言語は有限であるため、明らかに規則的です。4文字のアルファベットから3文字の場合、簡単です。
(abc|abd|acb|acd|bac|bad|bcd|bdc|cab|cad|cbd|cdb|dab|dac|dbc|dcb)
明らかに、これはより多くの文字とより大きなアルファベットで急いで手に負えなくなります。:-)
GNUのオプション--perl-regexp
(short -P
)は、grep
先読みパターンを含むより強力な正規表現を使用します。次のパターンは、この文字が単語の残りに表示されない各文字を探します。
grep -Pow '((\w)(?!\w*\g{-1})){10}'
ただし、実行時の動作は、\w*
ほぼ無限の長さになる可能性があるため、非常に不適切です。に制限できますが\w{,8}
、10文字の単語制限を超えてチェックすることもできます。したがって、次のパターンは最初に正しい語長をチェックします。
grep -Pow '(?=\w{10}\b)((\w)(?!\w*\g{-1})){10}'
テストファイルとして、約500 MBの大きなファイルを使用しました。
更新:
貪欲でない演算子(\w*?
)または所有演算子((...){10}+
)の実行時の動作に大きな変化はありませんでした。オプションの置き換えは少し速いようです-w
:
grep -Po '\b(?=\w{10}\b)((\w)(?!\w*\g{-1})){10}\b'
バージョン2.13から2.18へのgrepの更新は、はるかに効果的でした。テストファイルの所要時間はわずか6秒です。
\w{,8}?
)を使用すると、ある種の入力に役立つことがわかりました(あまり重要ではありませんが)。\g{-1}
GNU grepのバグを回避するための良い使用法。
\g{-1}
は、パターンが場所に依存しなくなるためです。この形式では、より大きなパターンの一部として使用できます。
Perlソリューション:
perl -lne 'print if (!/(.)(?=$1)/g && /^\w{10}$/)' file
しかし、それは動作しません
perl -lne 'print if (!/(.)(?=\1)/g && /^\w{10}$/)' file
または
perl -lne 'print if ( /(.)(?!$1)/g && /^\w{10}$/)' file
perl v5.14.2およびv5.18.2でテスト済み