web-dev-qa-db-ja.com

Javascript:負の後読み相当?

Javascriptの正規表現で negative lookbehind と同等の方法を実現する方法はありますか?特定の文字セットで始まらない文字列を照合する必要があります。

一致する部分が文字列の先頭で見つかった場合、失敗することなくこれを行う正規表現を見つけることができないようです。ネガティブルックビハインドが唯一の答えのようですが、javascriptにはそれがありません。

編集:これは私が働きたい正規表現ですが、そうではありません:

(?<!([abcdefg]))m

したがって、「jim」または「m」の「m」に一致しますが、「jam」には一致しません

127
Andrew Ensley

Lookbehind Assertions got accepted into ECMAScript specification in 2018.これまでのところ、 V8 でのみ実装されています。したがって、Chromeのみの環境( Electron など)または Node 向けに開発している場合は、すぐに後読みを使用できます!

肯定的な後読みの使用法:

console.log(
  "$9.99  €8.47".match(/(?<=\$)\d+(\.\d*)?/) // Matches "9.99"
);

ネガティブな後読みの使用法:

console.log(
  "$9.99  €8.47".match(/(?<!\$)\d+(?:\.\d*)/) // Matches "8.47"
);

プラットフォームのサポート:

38
Okku

Javascriptは negative lookahead をサポートするため、それを行う1つの方法は次のとおりです。

  1. 入力文字列を逆にします

  2. 逆正規表現と一致

  3. マッチを逆にして再フォーマットする


const reverse = s => s.split('').reverse().join('');

const test = (stringToTests, reversedRegexp) => stringToTests
  .map(reverse)
  .forEach((s,i) => {
    const match = reversedRegexp.test(s);
    console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
  });

例1:

次の@ andrew-ensleyの質問:

test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)

出力:

jim true token: m
m true token: m
jam false token: Ø

例2:

@neaumusicコメント(match max-height だがしかし line-height、トークンはheight):

test(['max-height', 'line-height'], /thgieh(?!(-enil))/)

出力:

max-height true token: height
line-height false token: Ø
79
JBE

intが前にないすべてのunsignedを検索するとします。

ネガティブな後読みのサポート:

(?<!unsigned )int

ネガティブな後読みのサポートなし:

((?!unsigned ).{9}|^.{0,8})int

基本的には、前のn個の文字を取得し、負の先読みとの一致を除外するだけでなく、前のn個の文字がない場合にも一致させることです。 (nは後読みの長さです)。

したがって、問題の正規表現:

(?<!([abcdefg]))m

に変換されます:

((?!([abcdefg])).|^)m

キャプチャグループを操作して、興味のある文字列の正確な場所を見つけるか、特定の部分を別のものに置き換えたい場合があります。

56
Kamil Szot

Mijojaの戦略は特定のケースで機能しますが、一般的には機能しません。

js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
   function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]AMA

次に、目的がdouble-lに一致することですが、その前に「ba」が付いている場合ではない例を示します。 「balll」という単語に注意してください。最初の2つのlは抑制されるはずですが、2番目のペアと一致するはずです。しかし、最初の2つのlを照合し、その一致を誤検出として無視することにより、正規表現エンジンはその一致のendから進み、誤検出内の文字を無視します。

41
Jason S

つかいます

newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});
33
Mijoja

文字セットを無効にすることで、非キャプチャグループを定義できます。

(?:[^a-g])m

...これは、すべてのm[〜#〜] not [〜#〜]の前にこれらの文字が続くすべてに一致します。

9
Klemen Slavič

これは、Node.js 8でstr.split(/(?<!^)@/)を実現した方法です(後読みをサポートしていません):

str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()

動作しますか?はい(ユニコードは未テスト)。不快?はい。

0
Fishrock123

これは効果的にそれを行います

"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null

検索と置換の例

"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"

これが機能するには、負の後ろ読み文字列が1文字でなければならないことに注意してください。

0
Curtis Yallop

前述のように、JavaScriptでは後読みが可能になりました。古いブラウザでは、まだ回避策が必要です。

結果を正確に提供する後読みなしで正規表現を見つける方法はないと思います。できることは、グループを操作することだけです。正規表現_(?<!Before)Wanted_があるとします。ここで、Wantedは照合する正規表現であり、Beforeは照合の前にすべきでないものをカウントする正規表現です。最善の方法は、正規表現Beforeを無効にし、正規表現NotBefore(Wanted)を使用することです。望ましい結果は、最初のグループ_$1_です。

あなたの場合、_Before=[abcdefg]_は否定しやすい_NotBefore=[^abcdefg]_です。したがって、正規表現は[^abcdefg](m)になります。 Wantedの位置が必要な場合は、NotBeforeもグループ化する必要があるため、目的の結果は2番目のグループになります。

Beforeパターンの一致が固定長nを持っている場合、つまり、パターンに反復トークンが含まれていない場合、Beforeパターンの否定を避け、正規表現を使用できます。 _(?!Before).{n}(Wanted)_、ただし最初のグループを使用するか、正規表現_(?!Before)(.{n})(Wanted)_を使用して2番目のグループを使用する必要があります。この例では、パターンBeforeは実際には固定長、つまり1であるため、正規表現_(?![abcdefg]).(m)_または_(?![abcdefg])(.)(m)_を使用します。すべての一致に興味がある場合は、gフラグを追加します。コードスニペットを参照してください。

_function TestSORegEx() {
  var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
  var reg = /(?![abcdefg])(.{1})(m)/gm;
  var out = "Matches and groups of the regex " + 
            "/(?![abcdefg])(.{1})(m)/gm in \ns = \"" + s + "\"";
  var match = reg.exec(s);
  while(match) {
    var start = match.index + match[1].length;
    out += "\nWhole match: " + match[0] + ", starts at: " + match.index
        +  ". Desired match: " + match[2] + ", starts at: " + start + ".";   
    match = reg.exec(s);
  }
  out += "\nResulting string after statement s.replace(reg, \"$1*$2*\")\n"
         + s.replace(reg, "$1*$2*");
  alert(out);
}
_
0

あなたのケースを使用して、置換したい場合m何か、例えば大文字のMに変換すると、キャプチャグループのセットを無効にできます。

([^a-g])mに一致し、$1Mに置き換えます

"jim jam".replace(/([^a-g])m/g, "$1M")
\\jiM jam

([^a-g])は、^範囲内の任意のchar not(a-g)と一致し、最初のキャプチャグループに保存するため、$1でアクセスできます。

したがって、imjimを見つけ、それをiMに置き換えて、結果としてjiMになります。

0
Traxo