【问题标题】:How to detect if a regex is replacable with a static text search?如何检测正则表达式是否可以用静态文本搜索替换?
【发布时间】:2019-07-15 18:52:47
【问题描述】:

如何检测某个正则表达式字符串是否“简单”,即可以将其替换为简单字符串(从而完全避免使用正则表达式)。

例如:

input regex        simple text form (if possible)
--------------------------------------------------
foo\.bar     --->  foo.bar
foo          --->  foo
ba\[12\]r    --->  ba[12]r
ba.*foo      --->  (not possible to represent as plain string)

基本上,我正在寻找与this answer 中描述的神话RegExp.escape 相反的RegExp.unescape,它要么与上述RegExp.escape 相反,要么以某种方式报告转换是不可能的.

正在寻找 JavaScript 解决方案,但 Java 也可以接受。

【问题讨论】:

  • 类似if (s.indexOf(s.replace(/\\([^])/g, '$1')) > -1) { console.log("Yes, it is 'simple'"); }?不过,这有时会导致误报。就像abc \wat 正则表达式和abc wat 字符串一样。
  • @WiktorStribiżew 你能解释一下你在那里做了什么吗?我很难跟上。
  • 嗯,这就是你的逻辑:删除转义并检查字符串是否包含新字符串。我认为它不会在 100% 的情况下起作用。
  • [^] 在做什么?
  • 这似乎很容易写...直到您意识到您不仅需要搜索元字符,而且还必须为\c\u\0 编写解析器。当然可行,但不是一件小事。

标签: javascript java regex


【解决方案1】:

基本上,我正在寻找与this answer 中描述的神话RegExp.escape 的对立面,即RegExp.unescape,它要么与所提到的RegExp.escape 相反,要么以某种方式报告无法进行转换.

这个函数应该可以处理大多数情况。如果无法进行转换,则返回<em>undefined</em>。它没有(但可以扩展到)做的是 e。 G。将a{3} 转换为aaa 或将[a] 转换为a

function cape(inre)
{
  if (/[iy]/.test(inre.flags)) return // these flags are not "simple"
  instr = inre.source
  outstr = ''
  special = '\\^$*+?.()|{}[]'
  // these so-called non-special characters after \ are not "simple":
  non_special = 'bBdDsSwW123456789'
  function pint(base, size)
  { // helper function for \0, \xhh and \uhhhh
    for (n = l = 0; l < size && !isNaN(d = parseInt(instr[i+1], base)); ++i, ++l)
      n = n*base+d
    return String.fromCharCode(n)
  }
  for (i = 0; c = instr[i]; outstr += c, ++i)
  { // convert input sequence to output text if possible
    if (c == '\\')
    {
      if (0 <= special.indexOf(c = instr[++i])) ; else
      if (0 <= non_special.indexOf(c)) return; else
      if (c == 'c') c = String.fromCharCode(instr.charCodeAt(++i)&31); else
      if (c == 'f') c = '\f'; else
      if (c == 'n') c = '\n'; else
      if (c == 'r') c = '\r'; else
      if (c == 't') c = '\t'; else
      if (c == 'v') c = '\v'; else
      if (c == '0') c = pint(8, 3); else
      if (c == 'x') c = pint(16, 2); else
      if (c == 'u') c = pint(16, 4)
    }
    else
      if (0 <= special.indexOf(c)) return
  }
  return outstr
}
console.log('input regex        simple text form (if possible)')
console.log('--------------------------------------------------')
testcases = [/foo\.bar/, /foo/, /ba\[12\]r/, /ba.*foo/]
for (i in testcases)
  s = testcases[i],
  console.log(s.source, ' '.repeat(11-s.source.length), '---> ', cape(s))

【讨论】:

  • 这应该与像 \\ 这样的输入中断
  • 它为什么会坏掉?它产生 \\ ---> \, i。 e.一个反斜杠的正确字符串。
  • 因为当 \\ 是最后一个字符时,instr[++i] 应该在字符串之外
  • RegExp.source 中的 \\ 不是一个字符,而是两个。
  • 好吧,我误解了 ++i 在链式 IF 中的两次可能已经离开了“源”字符串的长度,但无法理解为什么它没有。
【解决方案2】:

不转义是不够的,它归结为解析整个正则表达式。几乎任何非单词字符都有含义,因此不能简单地检测到。仅寻找反斜杠是远远不够的 - 考虑以下情况:

  • Once[.]{1,1} 没有转义,但很明显它可能是一个字符串
  • \x31\x{0032}也很明显
  • fo{2}d 更明显,但是通过代码识别这个代码并非易事,虽然

您首先必须优化给定的正则表达式以删除所有冗余并替换所需的字符,然后查看剩下的内容。这就是解析它的重点。

【讨论】:

  • 就我而言,这些例子可能不会被发现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 2019-11-03
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多