1.すべての始まり
最近、単純化されたBBCodeに類似した形式、つまりABBYY Lingvo辞書のソース形式-DSL(辞書仕様言語)でテキストファイルを処理する別のユーティリティを作成する必要がありました。 (別のDSL (ドメイン固有言語)と混同しないでください-下位語が上位語の同義語である場合の興味深いケースです)。
言語では角括弧内のタグを使用し、角括弧はプレーンテキストの一部として使用する場合は円記号でエスケープできると言うだけで十分です。
ユーティリティのタスクの1つは、エスケープされた組み合わせを除き、これらのタグを見つけることでした。
最近、JavaScriptの正規表現で(個人的な目的で)後読みアサーションを使用できるため、特にこの種の後読みでは可変長式を使用できるため、このツールを使用して検索を実装できるかどうか疑問に思いました。
2.予備的なコメント
さらに実験するためには、いくつかの新しいJavaScript機能に精通する必要があります。
1. テンプレートリテラル -変数補間を使用した待望の行。
2. String.raw() 。 この関数の機能は、Perlの単一引用符およびPythonの接頭辞
r''
と比較できます。これらはすべて、特殊なエスケープ文字のリテラル解釈を使用して文字列を作成するのに役立ちます。
3. 後読みアサーション (Google ChromeおよびNode.jsでそれらをアクティブにする方法を含む)。
3.実装
検索と検証のトライアル(単純な)実装を使用したスクリプトコード:
/******************************************************************************/ 'use strict'; /******************************************************************************/ const r = String.raw; const startOfString = '^'; const notEscapeSymbol = r`[^\x5c]`; const escapedEscapeSymbols = r`(?:${startOfString}|${notEscapeSymbol})(?:\x5c{2})+`; const tag = r`\x5b[^\x5d]+\x5d`; const tagRE = new RegExp( `(?<=${startOfString}|${notEscapeSymbol}|${escapedEscapeSymbols})${tag}`, 'g' ); console.log(r`[tag]text[/tag]`.match(tagRE)); console.log(r`\\[tag]text\\\\[/tag]`.match(tagRE)); console.log(r`\[tag]text\\\[/tag]`.match(tagRE)); /******************************************************************************/
まず、Pythonの
r''
プレフィックスのような短い形式を使用できるように、
String.raw
同義語を作成します。
次に、将来の正規表現のコンポーネントを作成します。
右のタグの前に3つのオプションのいずれかを付けることができるという前提から進みました。行の先頭、バックスラッシュを除く任意の文字、エスケープされたバックスラッシュ(つまり、2つのバックスラッシュの組み合わせ)。 この場合、スラッシュをエスケープする文字がエスケープされないことを確認する必要があります:つまり、タグの前に偶数個のバックスラッシュを置くことができ、その前に、行の先頭またはそれら以外の文字を置くことができます。
したがって、複雑な正規表現の4つの重要な要素が必要です。タグ自体とその3つの有効な先行要素-行の先頭、バックスラッシュを除く任意の文字、エスケープされたスラッシュまたはその繰り返し。 3番目のタグの前身は、最初の2つの前身のいずれかと任意の数量のバックスラッシュのペアの組み合わせとして表すことができます。
私の目に波及しないように、バックスラッシュと角括弧のすべてのリテラル文字を16進リテラル(
[ — \x5b, \ — \x5c, ] — \x5d
)に
[ — \x5b, \ — \x5c, ] — \x5d
。
パーツからコンパイルされた正規表現に相当するものは、次の組み合わせになります(
tagRE
直接割り当てることにより、最初のパーツ全体の代わりに使用できます)。
/(?<=^|[^\x5c]|(?:^|[^\x5c])(?:\x5c{2})+)\x5b[^\x5d]+\x5d/g
スクリプトの最後に、有効なタグとエスケープされたタグの最小限のセットで結果の式がテストされます。 最初の行には、行の先頭とバックスラッシュ以外の文字の後のタグが含まれます。 2行目には、エスケープされたバックスラッシュの後のタグが含まれます。バックスラッシュは、行の先頭またはそれ以外の文字のいずれかが先行します。 3行目にはエスケープタグが含まれています。
次の結果がコンソールに出力されます。
[ '[i]', '[/i]' ]
[ '[i]', '[/i]' ]
null
ソリューションを評価する場合、2つの予約を念頭に置く必要があります。
1.これは、量産用ではなく、家庭での使用のための実装です(Node.jsおよびGoogle Chromeですぐに使用できるアサーションが他のブラウザーに実装されないまで)。
2.この式は、タグ自体の内容の正確性を検証するためのものではなく、エスケープされた組み合わせと区別するためのものです。
検出されなかったリスクを指摘し、最適化のヒントをいただければ幸いです。