【问题标题】:Using javascript regex to remove multiple backslashes while preserving \n special character使用 javascript 正则表达式删除多个反斜杠,同时保留 \n 特殊字符
【发布时间】:2019-09-12 22:59:45
【问题描述】:

我们正在使用 JS 加载 JSON 数据,这些数据通常在换行符之前有多个反斜杠。示例:

{
    "test": {
        "title": "line 1\\\\\\\nline2"
    }
}

我已经使用替换尝试了各种 RegEx 模式。 “奇怪”,如果有偶数个反斜杠,它们似乎可以工作,但不是奇数。

这个带有 2 个反斜杠的示例有效:

"\\n".replace(/\\(?=.{2})/g, '');

虽然这个样本,3 没有:

"\\\n".replace(/\\(?=.{2})/g, '');

下面是运行中的 js:

console.log('Even Slashes:');
console.log("\\n".replace(/\\(?=.{2})/g, ''));
console.log('Odd Slashes:');
console.log("\\\n".replace(/\\(?=.{2})/g, ''));

【问题讨论】:

  • \n 是换行符的转义序列。 \\ 是反斜杠字符的转义序列。所以\\n 是一个反斜杠,后跟一个n\\\n 是一个反斜杠,后跟一个换行符,依此类推。
  • 跟进@p.s.w.g 说。您是否要删除换行符之前的所有反斜杠?
  • 只需尝试将\\ 甚至更好的\\+ 删除为空字符串,这只会删除一次或多次出现的文字\ ,如果确实它们,它根本不会触及你的换行符是换行符,而不是文字反斜杠,后跟文字 n
  • @JuanMendes -- 是的,我正在尝试删除换行符之前的所有反斜杠。
  • @PushpeshKumarRajwanshi,谢谢,但这些解决方案都不起作用。

标签: javascript json regex


【解决方案1】:

我认为您正在尝试删除换行符之前的所有反斜杠:str.replace(/\\+\n/g, "\n")

另外,你可能误会how escape sequences work

  • "\\" 是一个反斜杠

  • "\\n" 是一个反斜杠,后跟字母 n

请参阅下面的代码以获取解释,并注意 Stack Overflow 的控制台输出正在重新编码字符串,但如果您检查实际的开发工具,最好显示编码的字符。

const regex = /\\+\n/g;
// This is "Hello" + [two backslashes] + "nworld"
const evenSlashes = "Hello\\\\nworld";
// This is "Hello" + [two backslashes] + [newline] + "world"
const oddSlashes = "Hello\\\\\nworld";
console.log({
   evenSlashes,
   oddSlashes,
   // Doesn't replace anything because there's no newline on this string
   replacedEvenSlashes: evenSlashes.replace(regex, "\n"),
   // All backslashes before new line are replaced
   replacedOddSlashes: oddSlashes.replace(regex, "\n")
});

【讨论】:

  • 谢谢@Juan!不幸的是,我们不能 100% 确定它是否正确转义。可以有任意数量的反斜杠(偶数或奇数)。
  • @shackleton 这没有意义,在 even 的情况下没有新行。如果在这种情况下,它本来是一个换行符,但它被错误编码,在它被错误编码后你无法修复它,因为没有办法知道它应该是一个反斜杠,一个新行,还是只是一个n
【解决方案2】:

正如我在之前的评论中提到的,您在这里处理两个不同的转义序列:

  • \n 是换行符的转义序列,即 Unicode Character 'LINE FEED (LF)' (U+000A)
  • \\ 是反斜杠的转义序列,即 Unicode 字符 'REVERSE SOLIDUS' (U+005C)

虽然这些转义序列在源代码中是两个字符,但它们实际上只代表内存中的一个字符。

观察:

const toEscaped = s => s.toSource().match(/"(.*)"/)[0];
['\n', '\\n', '\\\n', '\\\\n', '\\\\\n']
  .forEach(s => console.log(`There are ${s.length} character(s) in ${toEscaped(s)}`))

这也适用于正则表达式。 \n 实际上算作一个字符,因此前瞻 (?=.{2}) 也会尝试捕获前面的 \,这就是为什么您可能会看到替换的工作方式有些奇怪。

但是,根据阅读您的一些 cmets,听起来您可能正在处理不正确的编码。例如,您可能会遇到用户在输入字段中输入foo\nbar 的情况,这会被解释为文字\,后跟n(即"foo\\nbar"),现在您想将其解释为换行符字符,(即"foo\nbar")。在这种情况下,您实际上并没有尝试删除 \ 字符,而是尝试将字符序列 \ + n 转换为 \n

以下代码 sn-p 显示如何执行 \\\n 的转义序列替换:

const toEscaped = s => s.toSource().match(/"(.*)"/)[0];
const toHex = s => Array.from(s).map((_, i) => s.charCodeAt(i).toString(16).padStart(2, '0')).join('+');
['\n', '\\n', '\\\n', '\\\\n', '\\\\\n']
  .map(s => ({ a: s, b: s.replace(/\\n/g, '\n').replace(/\\\\/g, '\\') }))
  .forEach(({a, b}) => console.log(`${toEscaped(a)} --> ${toHex(b)}`))

并且两者"\n"替换"\\n"并删除它前面的"\\"字符试试这样:

const toEscaped = s => s.toSource().match(/"(.*)"/)[0];
const toHex = s => Array.from(s).map((_, i) => s.charCodeAt(i).toString(16).padStart(2, '0')).join('+');
['\n', '\\n', '\\\n', '\\\\n', '\\\\\n']
  .map(s => ({ a: s, b: s.replace(/\\+[n\n]/g, '\n') }))
  .forEach(({a, b}) => console.log(`${toEscaped(a)} --> ${toHex(b)}`))

【讨论】:

    【解决方案3】:

    要从源文本中删除所有转义转义,它是
    查找:/([^\\]|^)(?:\\\\)+/g替换\1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-23
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多