简体   繁体   中英

javascript regex of a javascript string

I need to match a javascript string, with a regular expression, that is a string enclosed by single quote and can only contain a backslashed single quote.

The examples string that i would match are like the following:

'abcdefg'
'abc\'defg'
'abc\'de\'fg'

This is the regex that matches all valid JavaScript literal string (that is surrounded by single quote ' ) and reject all invalid ones. Note that strict mode is assumed.

/'(?:[^'\\\n\r\u2028\u2029]|\\(?:['"\\bfnrtv]|[^\n\r\u2028\u2029'"\\bfnrtvxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})|\\(?:\n|\r\n|\r(?!\n)|[\u2028\u2029]))*'/

Or a shorter version:

/'(?:[^'\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*'/

The regex above is based on the definition of StringLiteral (ignoring the double quoted version) specified in ECMAScript Language Specification, 5.1 Edition published in June 2011.

The regex for the JavaScript literal string surrounded with double quote " is almost the same:

/"(?:[^"\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*"/

Let's dissect the monster (the longer version, since it is direct translation from the grammar):

  • A StringLiteral (ignoring the double quote version) starts and ends with ' , as it can be seen in the regex. In between the quotes is an optional sequence of SingleStringCharacter . This explains the * - 0 or more characters.

  • SingleStringCharacter is defined as:

    \nSingleStringCharacter :: \n       SourceCharacter but not one of ' or \\ or LineTerminator \n       \\ EscapeSequence \n       LineContinuation \n

    [^'\\\\\\n\\r\
\
] corresponds to the first rule

    \\\\(?:['"\\\\bfnrtv]|[^\\n\\r\
\
'"\\\\bfnrtvxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}) corresponds to the second rule

    \\\\(?:\\n|\\r\\n|\\r(?!\\n)|[\
\
]) corresponds to the third rule

  • Let's look at the first rule: SourceCharacter but not one of ' or \\ or LineTerminator . This first rule deals with "normal" characters.

    SourceCharacter is any Unicode unit.

    LineTerminator is Line Feed <LF> ( \ or \\n ), Carriage Return <CR> ( \ or \\r ), Line Separator <LS> ( \
 ) or Paragraph Separator <PS> ( \
 ).

    So we will just use a negative character class to represent this rule: [^'\\\\\\n\\r\
\
] .

  • For the second rule, which deals with escape sequences, you can see \\ before EscapeSequence , as it appears in the regex. As for EscapeSequence , this is its grammar (strict mode):

    \nEscapeSequence :: \n        CharacterEscapeSequence \n        0 [lookahead ∉ DecimalDigit] \n        HexEscapeSequence \n        UnicodeEscapeSequence \n

    ['"\\\\bfnrtv]|[^\\n\\r\
\
'"\\\\bfnrtvxu0-9] is the regex for CharacterEscapeSequence . It can actually be simplified to [^\\n\\r\
\
xu0-9]

    The first part is SingleEscapeCharacter , which includes ' , " , \\ , and for control characters b , f , n , r , t , v .

    The second part is NonEscapeCharacter , which is SourceCharacter but not one of EscapeCharacter or LineTerminator . EscapeCharacter is defined as SingleEscapeCharacter , DecimalDigit or x (for hex escape sequence) or u (for unicode escape sequence).

    0(?![0-9]) is the regex for the second rule of EscapeSequence . This is for specifying null character \\0 .

    x[0-9a-fA-F]{2} is the regex for HexEscapeSequence

    u[0-9a-fA-F]{4} is the regex for UnicodeEscapeSequence

  • The third rule deals with string that spans multiple lines. Let's look at the grammar of LineContinuation and other related:

     LineContinuation :: \\ LineTerminatorSequence LineTerminatorSequence :: <LF> <CR> [lookahead ∉ <LF> ] <LS> <PS> <CR> <LF> 

    \\\\(?:\\n|\\r\\n|\\r(?!\\n)|[\
\
]) corresponds to the above grammar.

Try this one:

/'(?:[^'\\]|\\'|\\(?!'))*'/

Test it in your console:

/'(?:[^'\\]|\\'|\\(?!'))*'/.exec("'abc\\\'de\\\'fg'")

It'll match

  • Any number of characters that are:
    • NOT ' or \\ (except)
    • \\' (or)
    • \\ (not followed by ' )

If you want it to match the entire string, use the ^ start-of-string and $ end-of-string markers:

/^'(?:[^'\\]|\\'|\\(?!'))*'$/

... which will match 'string' , 'string\\'s are awesome' but not 'string's are awesome' or 'string's

it's not that hard...

Also, you need to detect some other possible chars sequences like \\n , \\r or \\\\ , breaking a line without escaping is not valid in javascript, you must use the \\n sequence.

/^'([^\\'\n\r]|\\'|\\n|\\r|\\\\)*'$/

In execution:

var sample = ["'abcdefg'", // Valid
              "'abc\\'defg'", // Valid
              "'abc\\'de\\'fg'", // Valid
              "'abc\\'\\r\\nde\\'fg'", // Valid
              "'abc\\'\r\nde\\'fg'", // Invalid
              "'abc'def'" // Invalid
             ];
for(var i = 0; i < sample.length; i++)
    console.log(sample[i].match( /^'([^\\'\n\r]|\\'|\\n|\\r|\\\\)*'$/ ));
  1. ^ tell to the matcher that the next condition must match the begining of the string
  2. ' will match the ' delimiter
  3. ( opens a group
  4. [^\\\\'\\n\\r] matches anything different from \\ and ' , and will not match the special \\n and \\r characters
  5. | if the condition above didn't match anything, the right side of | will be tested
  6. \\\\' will match \\'
  7. \\\\n will match a \\n literal string
  8. |\\\\r or will match a \\r literal string
  9. |\\\\\\\\ or will match a \\\\ literal string
  10. )* close the group and allow it to repeat multiple times and allow it to do not exist (empty string for example)
  11. ' will match the final ' delimiter
  12. $ tell to the matcher that this must be the and of the string

Try this

/^'([az]*(?:\\')?[az])+'$/

\n

See example here

str = 'abc\'de\'fg';

match = str.match(/^([a-z\\']+)$/g);

Tested in Firebug console. Works with or without the escape chars.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM