javascript regex-代替の背後を見ますか?


143

以下は、ほとんどの正規表現実装で正常に機能する正規表現です。

(?<!filename)\.js$

これは、filename.jsを除いて、.jsで終わる文字列の.jsに一致します。

Javascriptには後置正規表現がありません。誰かが同じ結果を達成し、JavaScriptで動作する代替正規表現をまとめることができますか?

ここにいくつかの考えがありますが、ヘルパー関数が必要です。私は正規表現だけでそれを達成したいと思っていました:http : //blog.stevenlevithan.com/archives/mimic-lookbehind-javascript


3
特定のファイル名またはファイル名のリストをチェックする必要があるだけなら、なぜ2つのチェックを使用しないのですか?それが.jsで終わっているかどうかを確認し、それが終わっている場合は、filename.jsと一致していないこと、またはその逆を確認します。
si28719e

3
アップデート:lookbehindsは、提案段階3にまだあるしかしことをD注:最新の公共Chromeバージョン(V62)は、(おそらく実験は)箱から出してlookbehinds github.com/tc39/proposal-regexp-lookbehind。そのため、JavaScriptがサポートするようになるまでしばらく時間がかかる場合があります。本番環境での使用には注意してください。
Eirik Birkeland 2017年

2
#更新:ES2018には後読みアサーション プラスが含まれます:-dotAll モード(sフラグ)-後読みアサーション-名前付きキャプチャグループ-Unicodeプロパティエスケープ
アシュリークールマン

2
ただ、使用(?<=thingy)thingyのための正の後読み(?<!thingy)thingyするために、負の後読み今ではそれらをサポートしています。
КонстантинВан

7
@ K._ 2018年2月現在、それはまだ真実ではありません!! また、ブラウザーとエンジンが仕様(現在ドラフト版)を実装する必要があるため、しばらく時間がかかります。
Andre Figueiredo

回答:


64

^(?!filename).+\.js 私のために働く

テスト対象:

  • test.jsの一致
  • blabla.jsの一致
  • filename.jsが一致しません

この正規表現の適切な説明は、正規表現にあり、単語を含まない文字列と一致しますか?

先読みはJavaScriptのバージョン1.5以降で利用可能で、すべての主要なブラウザーでサポートされています

filename2.jsおよび2filename.jsに一致するように更新されましたが、filename.jsには一致しません

(^(?!filename\.js$).).+\.js


5
あなたがリンクした質問は、少し異なる問題について話しています。つまり、ターゲットの単語がどこにも含まれていない文字列を照合します。この1ははるかに簡単です:ない文字列に一致するで始まるターゲットワードを。
アランムーア

それは本当に素晴らしいです、filename2.jsやfilenameddk.jsのようなケースを見逃すだけです。これは一致しませんが、一致する必要があります。
ダニエル

9
@daniel先読みではなく後読みを求めましたが、なぜこの答えを受け入れたのですか?
hek2mgl

1
指定されたものは一致しませんa.js
inetphantom '17 / 03/16

1
後読み付きの元の正規表現はと一致しません2filename.jsが、ここで指定された正規表現は一致します。より適切なものはでしょう^(?!.*filename\.js$).*\.js$。つまり、*.js 以外のすべて に一致します*filename.js
weibeld

153

編集:ECMAScript 2018以降、後読みアサーション(制限なしでも)がネイティブでサポートされます

以前のバージョンでは、これを行うことができます:

^(?:(?!filename\.js$).)*\.js$

これは、後読み式が暗黙的に行っていることを明示的に行います。後読み式とその後の正規表現が一致しない場合は、文字列の各文字を確認し、その文字のみを一致させます。

^                 # Start of string
(?:               # Try to match the following:
 (?!              # First assert that we can't match the following:
  filename\.js    # filename.js 
  $               # and end-of-string
 )                # End of negative lookahead
 .                # Match any character
)*                # Repeat as needed
\.js              # Match .js
$                 # End of string

別の編集:

(特にこの回答が非常に賛成されているので)この目標を達成するはるかに簡単な方法があると言うのは私を悩ませます。すべての文字で先読みをチェックする必要はありません:

^(?!.*filename\.js$).*\.js$

同様に動作します:

^                 # Start of string
(?!               # Assert that we can't match the following:
 .*               # any string, 
  filename\.js    # followed by filename.js
  $               # and end-of-string
)                 # End of negative lookahead
.*                # Match any string
\.js              # Match .js
$                 # End of string

先行する文字がある場合を除いて、多くのケースで機能します。例:filename.js(works-nomatch)filename2.js(works-match)blah.js(works-match)2filename.js(機能しません-nomatch) ---とは言っても、後読みには今まで気付かなかったのと同じ制限があります...
ダニエル

9
@daniel:まあ、あなたの正規表現(後読みあり)も一致しません2filename.js。私の正規表現は、例の正規表現とまったく同じケースで一致します。
Tim Pietzcker、2011

私の世間知らずを許してください、しかしここで非捕獲グループの使用はありますか?文字列内の置換のために参照を収集しようとする場合にのみ役立つことが常にわかっています。私の知る限り、これも機能します^(?! filename \ .js $)。* \。js $
回答が必要です

1
正規表現では、文字列の先頭でのみ「filename.js」をチェックします。しかし、^(?!.*filename\.js$).*\.js$うまくいくでしょう。ncgroupがまだ必要になる可能性がある状況を考えてみてください...
Tim Pietzcker 2017年

このアプローチは次のように要約できます。Xの後ろを見るのではなく、Xの前に来るすべてのキャラクターを前に見てください。
Sarsaparilla

25

int前にないものをすべて検索したいとしますunsigned

否定的な後読みのサポート:

(?<!unsigned )int

否定的な後読みをサポートしない場合:

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

基本的には、先行するn個の文字を取得し、否定先読みを使用して一致を除外するだけでなく、前にn個の文字がない場合にも一致するようにします。(nは後読みの長さです)。

問題の正規表現:

(?<!filename)\.js$

に変換されます:

((?!filename).{8}|^.{0,7})\.js$

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


私はちょうどこの変換:(?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))(?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))いる私のニーズのためのトリックを行います。これを別の「現実の」シナリオとして提供するだけです。リンクを
Eirik Birkeland 2016年

私はあなたが意味したと思います:((?!unsigned ).{9}|^.{0,8})int
パンジー2017

@pansayはい。ありがとうございました。回答を修正しました。
Kamil Szot 2017

2
テキスト内で完全に一致させる必要がある場合でも機能する、より一般化された回答に感謝します(最初の^は非現実的です)。
ミロスMrdovic 2017

5

先を見ることはできても後ろを見ることもできる場合は、最初に文字列を逆にしてから先読みを行うことができます。もちろん、さらにいくつかの作業を行う必要があります。


8
この答えは、実際にいくつかの改善を使用できます。私にはもっとコメントのようです。
mickmackusa

2

これは、Tim Pietzckerの回答と同等のソリューションです(同じ回答のコメントも参照)。

^(?!.*filename\.js$).*\.js$

つまり、*.jsを除いて一致し*filename.jsます。

このソリューションに到達するには、否定的な後読みが除外するパターンを確認し、これらのパターンを否定的な先読みで正確に除外します。


-1

以下は、「Michael」を名として持つ人々の姓をキャプチャする方法を示す肯定的な後読みJavaScriptの代替です。

1)このテキストを考える:

const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

Michaelという名前の姓の配列を取得します。結果は次のようになります。["Jordan","Johnson","Green","Wood"]

2)解決策:

function getMichaelLastName2(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(person.indexOf(' ')+1));
}

// or even
    .map(person => person.slice(8)); // since we know the length of "Michael "

3)解決策を確認する

console.log(JSON.stringify(    getMichaelLastName(exampleText)    ));
// ["Jordan","Johnson","Green","Wood"]

ここのデモ:http : //codepen.io/PiotrBerebecki/pen/GjwRoo

以下のスニペットを実行して試してみることもできます。

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";



function getMichaelLastName(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(8));
}

console.log(JSON.stringify(    getMichaelLastName(inputText)    ));

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.