3

JavaScript で正規表現を使用して初歩的なレクサーを作成していますが、1 つに結合したい 2 つの正規表現 (一重引用符で囲まれた文字列用と二重引用符で囲まれた文字列用) があります。これらは私の 2 つの正規表現です (テスト目的で文字^と文字を追加しました)。$

var singleQuotedString = /^'(?:[^'\\]|\\'|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*'$/gi;
var doubleQuotedString = /^"(?:[^"\\]|\\"|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*"$/gi;

今、次のようにそれらを単一の正規表現に結合しようとしました:

var string = /^(["'])(?:[^\1\\]|\\\1|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*\1$/gi;

ただし、入力をテストすると、代わりに次の"Hello"World!"ように返されます。truefalse

alert(string.test('"Hello"World!"')); //should return false as a double quoted string must escape double quote characters

問題は、[^\1\\]グループに一致する以外の任意の文字\1(一重引用符または二重引用符 - 文字列の区切り文字) と\\(バックスラッシュ文字) に一致する必要があることだと考えました。

正規表現はバックスラッシュを正しく除外し、区切り記号に一致しますが、文字列内の区切り記号は除外しません。どんな助けでも大歓迎です。Crockford の鉄道図を参照して正規表現を記述したことに注意してください。

4

3 に答える 3

7

文字クラス内で一致したグループを参照することはできません: (['"])[^\1\\]. 代わりに次のようにしてみてください。

(['"])((?!\1|\\).|\\[bnfrt]|\\u[a-fA-F\d]{4}|\\\1)*\1

(さらにいくつかのエスケープを追加する必要がありますが、あなたは私のドリフトを取得します...)

簡単な説明:

(['"])             # match a single or double quote and store it in group 1
(                  # start group 2
  (?!\1|\\).       #   if group 1 or a backslash isn't ahead, match any non-line break char
  |                #   OR
  \\[bnfrt]        #   match an escape sequence
  |                #   OR
  \\u[a-fA-F\d]{4} #   match a Unicode escape
  |                #   OR
  \\\1             #   match an escaped quote
)*                 # close group 2 and repeat it zero or more times
\1                 # match whatever group 1 matched
于 2012-04-27T19:10:41.317 に答える
2

これもうまくいくはずです(生の正規表現)。
速度が重要な要素である場合、これは「展開」方式であり、この種の処理では最速であると言われています。

(['"])(?:(?!\\|\1).)*(?:\\(?:[\/bfnrt]|u[0-9A-F]{4}|\1)(?:(?!\\|\1).)*)*/1  

エキスパンド

(['"])            # Capture a quote
(?:
   (?!\\|\1).             # As many non-escape and non-quote chars as possible
)*

(?:                       
    \\                     # escape plus,
    (?:
        [\/bfnrt]          # /,b,f,n,r,t or u[a-9A-f]{4} or captured quote
      | u[0-9A-F]{4}
      | \1
    )
    (?:                
        (?!\\|\1).         # As many non-escape and non-quote chars as possible
    )*
)*

/1                # Captured quote
于 2012-04-27T19:25:01.753 に答える
0

まあ、小さい正規表現で代替演算子を使用するだけで、いつでもより大きな正規表現を作成できます

/(?:single-quoted-regex)|(?:double-quoted-regex)/

または明示的に:

var string = /(?:^'(?:[^'\\]|\\'|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*'$)|(?:^"(?:[^"\\]|\\"|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*"$)/gi;

最後に、コードの重複を避けたい場合は、コンストラクターを使用してこの正規表現を動的に構築できますnew Regex

var quoted_string = function(delimiter){
    return ('^' + delimiter + '(?:[^' + delimiter + '\\]|\\' + delimiter + '|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*' + delimiter + '$').replace(/\\/g, '\\\\');
    //in the general case you could consider using a regex excaping function to avoid backslash hell.
};

var string = new RegExp( '(?:' + quoted_string("'") + ')|(?:' + quoted_string('"') + ')' , 'gi' );
于 2012-04-27T18:45:45.520 に答える