使用regexp替换字符串会覆盖非匹配字符

时间:2018-05-03 11:43:49

标签: javascript regex

这个想法是在一个字符串中替换所有十进制数字,而小数点前的数字为零,因此.03 sqrt(.02)将成为0.03 sqrt(0.02)

请参阅下面的代码示例,问题是当小数点前面有一个替换时,替换会覆盖左括号。我认为括号与匹配字符串无关,是吗?

let s='.05 sqrt(.005) another(.33) thisShouldntChange(a.b) neither(3.4)'

s=s.replace(/(?:^|\D)\.(\d+)/g , "0.$1");

console.log(s)

2 个答案:

答案 0 :(得分:1)

进行初始群组捕获,而不是非捕获,并在替换中使用它:

s=s.replace(/(^|[^\d])\.(\d+)/g , "$10.$2");
//           ^---- capturing, not non-capturing

示例:

let s = '.05 sqrt(.005) another(.33) thisShouldntChange(a.b) neither(3.4)'

s=s.replace(/(^|[^\d])\.(\d+)/g , "$10.$2");

console.log(s)

  

我认为括号与匹配字符串无关,是吗?

确实如此,因为它匹配[^\d]

附注:As Wiktor points out,您可以使用\D代替[^\d]

附注2:JavaScript正则表达式最终获得lookbehind(在living specification中,并且将在ES2018规范快照中),因此使用现代 JavaScript环境将是负面的背后:

s=s.replace(/(?<!\d)\.(\d+)/g , "0.$1");
//           ^^^^^^^--- negative lookbehind for a digit

这基本上意味着“如果这里有一个数字,那就不匹配了”。 (还有肯定的 lookbehind,(?<=...)。)

示例:

let s = '.05 sqrt(.005) another(.33) thisShouldntChange(a.b) neither(3.4)'

s=s.replace(/(?<!\d)\.(\d+)/g , "0.$1");

console.log(s)

答案 1 :(得分:1)

括号是一个nn数字,因此它与[^\d]匹配并删除。

解决方案是在点之前匹配并捕获零件,然后使用替换后向引用插回。

使用

.replace(/(^|\D)\.(\d+)/g , "$10.$2")

请参阅regex demo

模式详情

  • (^|\D) - 捕获第1组(稍后从替换模式中引用$1):字符串的开头或任何非数字([^\d] = \D
  • \. - 一个点
  • (\d+) - 捕获第2组(后来用替换模式中的$2引用):1+位。

参见JS演示:

let s='.05 sqrt(.005) another(.33) thisShouldnt(a.b) neither(3.4)'

s=s.replace(/(^|\D)\.(\d+)/g , "$10.$2");

console.log(s)

请注意,$10.$2将由RegExp引擎解析为$1反向引用,然后是0.文本,然后是$2反向引用,因为在此只有2个捕获组模式,没有10个捕获组,因此$10不会被视为替换模式中的有效标记。