如何测试字符串是否包含无效的字符串文字?

时间:2017-05-01 06:45:26

标签: javascript php regex string

我有这样的正则表达式匹配字符串文字:

/"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'/

DEMO

如何测试给定的字符串是否包含无效(未闭合的字符串),如下所示:

echo "asd \\\"asd && rm

它应匹配:

  1. echo "foo
  2. echo "asd \\\"asd && rm
  3. echo "asd \" " asd && rm " \"
  4. 但不是:

    1. echo "asd \\\"asd" && rm
    2. echo "asd \"asd" && rm
    3. echo "asd \\\\\"asd" && echo " \" " && rm
    4. 如何使用javascript(没有特定的PCRE扩展名)创建此类正则表达式解决方案是首选。

      编辑:我已经使用php解决了这个问题:

      /(?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*')(*SKIP)(*F)|"/
      

      是否可以在javascript中执行相同的操作,还是需要解析字符串?

2 个答案:

答案 0 :(得分:2)

你的php模式实际上是错误的,因为它不适用于单引号。如果您使用"更改上一个["'],则可以轻松更正此问题。请注意,您也不需要使用变通方法[\s\S],因为pcre具有单行修饰符s:

/(?:"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')(*SKIP)(*F)|["']/s

然而,如果使用(*SKIP)(*FAIL)组合似乎引诱,它以低效的模式设计结束:以交替开始的非锚定模式。结果,对于不是引用的每个字符(在引用部分之外),交替的三个分支都没有被测试。

这就是为什么我建议一种更有效的方法,从一开始就检查字符串(锚定模式)并使用占有量词:

$p = '~(?:  [^"\']+ 
         |  " [^"\\\\]*  (?: \\\\. [^"\\\\]*  )*  "
         | \' [^\'\\\\]* (?: \\\\. [^\'\\\\]* )* \'
       )*+  # possessive quantifier
       .    # a character that can only be a quote (single or double) 
      ~xAs'; // modifiers: extended, Anchored, singleline

var_dump(preg_match($p, $str));

demo

由于量词是贪婪的(它需要一切可能)和占有(它禁止正则表达式引擎回溯),因此点匹配的字符只能是孤立引用(如果存在)(否则,模式失败)

与javascript相同的想法,除了你必须使用前瞻的原子性质来模拟占有量词:(?=(...))\1

var p = /^(?=((?:[^"']+|"[^"\\]*(?:\\[^][^"\\]*)*"|'[^'\\]*(?:\\[^][^'\\]*)*')*))\1./;
console.log(p.test(s));

您还可以构建状态机:

String.prototype.unbalancedQuotes = function () {
    var p = /[\\"']/g, state = {
        e: false, // escape state: index of the last quoted escape character or false
        q: undefined, // quote state: last opening quote or undefined
        update: function(m) {
            if ( this.e === m.index - 1 ) { // when the current character is escaped:
               this.e = false;  //set the escaped state to false
            } else {                        // otherwise:
               if ( this.q && m[0] == '\\' ) // if the character is a quoted backslash
                   this.e = m.index; // store the current index
               else // else change eventually the quote state
                   this.q = this.q == m[0] ? undefined : this.q || m[0];
            }
        }
    };

    while ( (m = p.exec(this)) !== null ) state.update(m);

    return Boolean(state.q);
};

var s = '"a\\h"bcd';

console.log(s);
console.log(s.unbalancedQuotes());

答案 1 :(得分:1)

在php中,我使用正则表达式解决了这个问题:

/(?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*')(*SKIP)(*F)|"/

在javascript中我创建了解析函数:

    function unclosed_strings(string) {
        if (!string.match(/["']/)) {
            return false;
        }
        var count = 0;
        string.match(/\\*["']/g).forEach(function(quote) {
            var slashes = quote.match(/\\/g);
            if (slashes && slashes.length % 2 === 0 || !slashes) {
                count++;
            }
        });
        return count % 2 !== 0;
    }
相关问题