4

私は正規表現の分野に不慣れです。
以下に投稿するのは、私のコードの単純化された例だけです。

test_1,some_2,foo,bar_4,文字列があります。たとえば、次の文字列に置き換えたいとしましょうtitle: test (1) title: some (2) title: foo () title: bar (4)

私が今持っているものは(これは動作します):

var test = "test_1,some_2,foo,bar_4,";
console.log(test.replace(/(.*?)(?:_(\d))?,/g, "title: $1 ($2)\n"));

出力:

title: test (1)
title: some (2)
title: foo ()
title: bar (4)

物事を正しくするために、最後の項目の後に昏睡状態を解消したいと考えています。リストは次のようになりますtest_1,some_2,foo,bar_4 (bar_4 の後にコンマなし)

したがって、新しいコードは次のとおりです。

var test = "test_1,some_2,foo,bar_4";
console.log(test.replace(/(.*?)(?:_(\d))?(?:,|$)/g, "title: $1 ($2) "));

何か間違ったものを出力します。最後に余分な空のマッチがあります:

title: test (1)
title: some (2)
title: foo ()
title: bar (4)
title:  ()

私の質問は次のとおりです。なぜですか?修正方法は?実際の正規表現に改善の可能性はありますか?

デモ jsFiddle

4

3 に答える 3

5

正規表現が空の文字列と一致するため、最後の誤検知一致が得られます。

"".replace(/(.*?)(?:_(\d))?(?:,|$)/g, "title: '$1' ('$2') ");

title: '' ('') 

したがって、あなたの場合、すべての文字が消費された後、空の文字列と一致します。

表示されているように、最初のグループが実際にはオプションではないことを考慮して、最初のグループを非オプションに変更することで制御できます。

/(.*?)(?:_(\d))?(?:,|$)/g
 --^^--

例えば、

var str = "test_1,some_2,foo,bar_4";
test.replace(/([a-z]+)(?:_(\d))?(?:,|$)/gi, "title: '$1' ('$2') ");

title: test (1) title: some (2) title: foo () title: bar (4)

あれは、

  • ([a-z]+):少なくとも1 つのアルファベット文字に一致し、かつ
  • gi: 文字列の大文字と小文字を区別しません。
于 2012-12-15T13:37:58.803 に答える
1

あなたの問題はあなたのパターンがあなたが望むものだけでなく空の文字列にも一致することです:

(.*?)  # matches any string (including an empty one) not containing \n
(?:_(\d))?  # it is an optional group
(?:,|$)  # it matches a comma or the end of the string

したがって、正規表現エンジンが文字列の終わりをパターンに対して評価すると、次のことがわかります。

  • 空の文字列が処理されているため、最初のグループが一致します
  • 2番目のグループはオプションであるため一致します
  • 文字列の終わりが処理されているため、3番目のグループが一致します

したがって、パターン全体が一致し、追加の一致が得られます。match文字列のメソッドを使用して、コンソールではっきりと確認できます

> s.match(/(.*?)(?:_(\d))?(?:,|$)/g)
  ["test_1,", "some_2,", "foo,", "bar_4", ""]

問題に対処するには、少なくとも2つのオプションがあります。

  • 空の文字列と一致しないが、それでもニーズに合うようにパターンの最初のグループを変更します(処理する必要のある文字列によって異なります)
  • 正規表現はそのままにしreplaceて、不要な部分を削除して返された文字列を処理します

最初のオプションはエレガントなものです。2つ目は、追加のコード行で簡単に実現できます。

> var result = s.replace(/(.*?)(?:_(\d))?(?:,|$)/g, "title: $1 ($2) ");
> result = result.slice(0, result.lastIndexOf("title"));
  "title: test (1) title: some (2) title: foo () title: bar (4) "
于 2012-12-16T11:40:15.057 に答える
1

最も簡単な解決策として、正規表現に一致する前に、元の文字列に末尾のコンマを追加するだけです。

于 2012-12-15T12:16:23.767 に答える