web-dev-qa-db-ja.com

排他的または正規表現

正規表現のヘルプを少し探しています。 "foo" OR "bar"で、両方ではない "-の文字列に一致する式を設計したいfoo "AND" bar "

私が何かをした場合...

/((foo)|(bar))/

foobar」と一致します。私が探しているものではありません。では、どちらかの用語が存在する場合にのみ正規表現を一致させるにはどうすればよいですか?

ありがとう!

29
SocialCensus

あなたは単一の正規表現でこれを行うことができますが、読みやすさのためにあなたは次のようなことをすることを勧めます...

(/foo/ and not /bar/) || (/bar/ and not /foo/)
9
Ed Guiness

これは私が使用するものです:

/^(foo|bar){1}$/

参照: http://www.regular-expressions.info/quickstart.html 繰り返し

31
Tristan

あなたの正規表現言語がそれをサポートしているなら、 negative lookaround を使用してください:

(?<!foo|bar)(foo|bar)(?!foo|bar)

これは、「foo」または「bar」の直前または直後にない「foo」または「bar」と一致します。

一致させようとしている文字列に他のトークン「foocuzbar」が含まれているかどうかは、質問や例からは明らかではありません。その場合、このパターンは機能しません。

テストケースの結果を次に示します(「true」は、パターンが入力で見つかったことを意味します)。

foo: true
bar: true
foofoo: false
barfoo: false
foobarfoo: false
barbar: false
barfoofoo: false
17
erickson

これは、「foo」と「bar」を受け取りますが、「foobar」と「blafoo」を取りません。「blabar」は受け取りません。

/^(foo|bar)$/

^ = mark start of string (or line)
$ = mark end of string (or line)

これは、「foo」と「bar」と「foo bar」と「bar-foo」を受け取りますが、「foobar」と「blafoo」と「blabar」を取りません:

/\b(foo|bar)\b/

\b = mark Word boundry
6
oriadam

「foo」と「bar」以外のコンテンツに関する動作、または一方が存在しない場合の一方の繰り返しを指定していません。例:「foo d」または「barbar ian」は一致する必要がありますか?

"foo"または "bar"のいずれか1つのインスタンスのみを含み、両方を含まず、同じインスタンスの複数のインスタンスを含まない文字列に一致させる場合、文字列内の他のものには関係なく(つまり、 "food"一致と「barbarian」は一致しません)、見つかった一致の数を返し、一致が1つだけ見つかった場合にのみ成功したと見なす正規表現を使用できます。たとえば、Perlの場合:

@matches = ($value =~ /(foo|bar)/g)  # @matches now hold all foos or bars present
if (scalar @matches == 1) {          # exactly one match found
  ...
}

同じターゲットの複数の繰り返しが許可されている場合(つまり、「野蛮な」一致)、この同じ一般的なアプローチを使用して、一致のリストをウォークし、一致がすべて同じテキストの繰り返しであるかどうか、または他のオプションかどうかを確認できます。も存在します。

3
Dave Sherohman

あなたは検討したいかもしれませんか?条件付きテスト。

(?(?=regex)then|else)

正規表現条件

2
Josh

私はこれが遅いエントリーであることを知っていますが、見ているかもしれない他の人を助けるためだけです:

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)
1
qmckinsey

真の排他的論理和が必要な場合は、正規表現ではなくコードで行います。 Perlの場合:

/foo/ xor /bar/

しかし、あなたのコメント:

一致:「foo」、「bar」非一致:「foofoo」「barfoo」「foobarfoo」「barbar」「barfoofoo」

あなたは本当に排他的またはを探していないことを示します。あなたは実際に「Does /foo|bar/正確に1回一致しますか?」

my $matches = 0;
while (/foo|bar/g) {
  last if ++$matches > 1;
}

my $ok = ($matches == 1)
1
cjm
\b(foo)\b|\b(bar)\b

そして、最初の キャプチャグループ のみを使用します。

0

このようなものを使用します。単語の周りのスペースをチェックするだけですが、\bまたは\Bを使用して境界線を確認するには\w。これは「foo」または「bar」に一致するため、念のため、空白も同様に置き換える必要があります。 (あなたが何かを交換していると仮定します。)

/\s((foo)|(bar))\s/
0
Robert K

これは単一の正規表現では実行できないと思います。境界は、照合対象に応じて機能する場合と機能しない場合があります。

私は各正規表現に対して個別に照合し、結果に対してXORを実行します。

foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
    # do someting...
0
Can Berk Güder

私はRegex Coachを試してみました:

x foo y
x bar y
x foobar y

gオプションをチェックすると、実際には3つの単語すべてに一致します。これは、一致するたびに再度検索するためです。
この動作を望まない場合は、式を固定できます。たとえば、Wordの境界でのみ一致させることができます。

\b(foo|bar)\b

問題に関するより多くのコンテキスト(データがどのように見えるか)を与えると、より適切な回答が得られる可能性があります。

0
PhiLho

単語の境界を使用すると、単一の単語を取得できます...

me@home ~  
$ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
Where is my bar of soap?  

me@home ~  
$ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
What the foo happened here?  

me@home ~  
$ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  
0
bill_the_loser