【问题标题】:How to test if string contain invalid string literals?如何测试字符串是否包含无效的字符串文字?
【发布时间】:2017-05-01 06:45:25
【问题描述】:

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

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

DEMO

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

echo "asd \\\"asd && rm

应该匹配:

  1. echo "foo
  2. echo "asd \\\"asd && rm
  3. echo "asd \" " asd && rm " \"

但不是:

  1. echo "asd \\\"asd" && rm
  2. echo "asd \"asd" && rm
  3. echo "asd \\\\\"asd" && echo " \" " && rm

如何使用 javascript(没有特定的 PCRE 扩展)创建这样的正则表达式解决方案是首选。

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

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

是否可以在 javascript 中做同样的事情,还是我需要解析字符串?

【问题讨论】:

  • @Alex 那应该解决什么问题?问题是匹配字符串中的数字,问题是访问属性。
  • 在您的问题中,您问如何创建“使用 javascript 的此类正则表达式解决方案”。我提供的链接显示了如何使用 JavaScript 来执行正则表达式。您也没有提到匹配的数字或访问您的问题中的属性。您能否提供显示您需要访问哪些属性的代码?这样我们才能找出访问它们的最佳方式。
  • @Alex 不是我的问题,但您链接的问题是关于使用属性和正则表达式来匹配数字。我的问题是如何创建匹配字符串文字的正则表达式。
  • @Alex 问题是关于检查字符串是否包含奇数个引号字符,如果引号之前没有斜杠甚至斜杠数。

标签: javascript php regex string


【解决方案1】:

您的 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());

【讨论】:

    【解决方案2】:

    在 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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-27
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 2017-11-16
      • 2014-07-23
      • 2020-11-03
      • 2017-11-21
      相关资源
      最近更新 更多