【问题标题】:How to replace double quotes nested in another double quotes with single quotes如何用单引号替换嵌套在另一个双引号中的双引号
【发布时间】:2021-02-04 08:38:31
【问题描述】:

我目前正在使用替换脚本来自动修复单引号和双引号。

但是,我找不到更改嵌套在另一个双引号内的双引号的解决方案

这样:

“这是在“abc”开头和结尾处的一些额外文字”

应该是

“这里有一些额外的文字,在'abc'开头和结尾”

目前,我只能使用简单的替换脚本自动修复这种类型,如果它位于其他引号旁边(例如““abc””)

.replaceAll("““", "“‘").replaceAll("””", "’”")

是否可以使用正则表达式来定位嵌套在另一个双引号中的任何双引号?

注意:重要的是引号是弯的(“”和'')而不是直的(“”和'')。

function fixTextarea(textarea) {
  textarea.value = textarea.value.replace(" ,", ",")
    .replaceAll(" ;", ";")
    .replaceAll(" .", ".")
    .replaceAll("  ", " ")
    .replaceAll("   ", " ")
    .replaceAll("“ ", "“")
    .replaceAll(" ”", "”")
    .replaceAll("““", "“‘")
    .replaceAll("””", "’”")
    .replaceAll(/(^|[-\u2014\s(\["])'/g, "$1\u2018")
    .replaceAll(/'/g, "\u2019")
    .replaceAll(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c")
    .replaceAll(/"/g, "\u201d")
};

function fixtext() {
  let textarea = document.getElementById("textarea1");
  textarea.select();
  fixTextarea(textarea);
}

window.addEventListener('DOMContentLoaded', function(e) {
  var area = document.getElementById("textarea1");

  var getCount = function(str, search) {
    return str.split(search).length - 1;
  };

  var replace = function(search, replaceWith) {
    if (typeof(search) == "object") {
      area.value = area.value.replace(search, replaceWith);
      return;
    }
    if (area.value.indexOf(search) >= 0) {
      var start = area.selectionStart;
      var end = area.selectionEnd;
      var textBefore = area.value.substr(0, end);
      var lengthDiff = (replaceWith.length - search.length) * getCount(textBefore, search);
      area.value = area.value.replace(search, replaceWith);
      area.selectionStart = start + lengthDiff;
      area.selectionEnd = end + lengthDiff;
    }
  };

});
<textarea class="lined" id="textarea1" name="textarea1" spellcheck="true" placeholder="" onpaste="console.log('onpastefromhtml')"></textarea>
<br><br>
<button onclick="fixtext()"> Fixit</button>

【问题讨论】:

  • 如果您显示的输入具有代表性,也许最简单的解决方案是获取外部引号内的字符串(只需将子字符串从索引 1 获取到长度 - 2),替换此中的所有引号内部字符串,并放回外部引号。
  • 很抱歉,由于我刚开始学习 javascript 和正则表达式,我无法理解您的建议。能详细点吗?

标签: javascript regex


【解决方案1】:

好吧,我之前的回答很烂。

现在只是为了好玩:一个嵌套引号解析实用程序,用于不带任何RegExp 的直引号和弯引号。

const {
  nestedDoubleQuotes2Single,
  nestedSingleQuotes2Double
} = nestedQuotesParser();
const singleCurly2Double = `‘Here’s some extra ‘text’ at the beginning ‘abc’ and at the end ’`;
const doubleCurly2Single = "“Here’s some extra “text” at the beginning “abc” and at the end ”";
const doubleStraight2Single = '"Here\'s some extra "text" at the beginning "abc" and at the end. "';
const singleStraight2Double = "'Here's some extra 'text' at the beginning 'abc' and at the end'";

console.log(nestedDoubleQuotes2Single(doubleCurly2Single, true));
console.log(nestedDoubleQuotes2Single(doubleStraight2Single));
console.log(nestedSingleQuotes2Double(singleStraight2Double));
console.log(nestedSingleQuotes2Double(singleCurly2Double, true));

function nestedQuotesParser() {
  let isCurly = false;
  const quoting = {
    get all() {
      return isCurly ? `“”‘’` : `""'`;
    },
    get single() {
      return isCurly ? `‘’` : `''`;
    },
    get double() {
      return isCurly ? `“”` : `""`;
    },
  };
  const reQuotDouble = m => quoting.single[quoting.all.indexOf(m)] || m;
  const reQuotSingle = m => quoting.double[quoting.all.indexOf(m) - 2] || m;
  const checkNestedSingle = (s, chr, i) =>
    ~quoting.all.indexOf(chr) && (i < s.length - 2 && (s[i - 1] === " " || s[i + 1] === " "));

  return {
    nestedDoubleQuotes2Single: (s, curly = false) => {
      isCurly = curly;
      return s.split("")
        .reduce((acc, chr, i) =>
          acc + (i > 0 && i < s.length - 1 &&
            ~quoting.all.indexOf(chr) ? reQuotDouble(chr) : chr), '');
    },
    nestedSingleQuotes2Double: (s, curly = false) => {
      isCurly = curly;
      return s.split("").reduce((acc, chr, i) =>
        acc + (s.length - i < s.length - 1 && checkNestedSingle(s, chr, i) ?
          curly && reQuotSingle(chr) || '"' :
          chr), "");
    },
  };
}

您的代码,使用此实用程序:

function fixTextarea(textarea) {
    let depth = 0; // <-- added
    const value = textarea.value.replace(" ,", ",")
        .replaceAll(" ;", ";")
        .replaceAll(" .", ".")
        .replaceAll("  ", " ")
        .replaceAll("   ", " ")
        .replaceAll("“ ", "“")
        .replaceAll(" ”", "”")
        .replaceAll(/(^|[-\u2014\s(\["])'/g, "$1\u2018")
        .replaceAll(/'/g, "\u2019")
        .replaceAll(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c")
        .replaceAll(/"/g, "\u201d");
    textarea.value = nestedDoubleQuotes2Single(value, true);
};

【讨论】:

  • /[^^“]“|”[^”$]/g 是当前问题的错误正则表达式。您使用正则表达式删除 之前和 之后的字符。此外,[^^“] 是一个损坏的模式,它匹配除^ 之外的任何字符,”[^”$] 也存在同样的问题。 ^$ 在字符类中不是特殊的。
【解决方案2】:

您可以跟踪引号嵌套的深度(无论是否双引号),并以这样的方式替换它们:在 even 深度上它们是双引号,而在 odd 深度它们是单引号。一种预防措施是排除 ’s 中的撇号(可能还有一些其他例外情况,撇号不应作为引号的结尾):

let s = "“Here’s some extra text at the beginning “abc” and at the end”";

let depth = 0;
let result = s.replace(/[“”‘]|’(?!s)/g, m => 
    "“‘".includes(m) ? "“‘"[depth++] : "”’"[--depth]);

console.log(result);

注意:这甚至可以解决引号配对错误的情况。

它可以像这样集成到您当前的功能中:

function fixTextarea(textarea) {
    let depth = 0; // <-- added
    textarea.value = textarea.value.replace(" ,", ",")
        .replaceAll(" ;", ";")
        .replaceAll(" .", ".")
        .replaceAll("  ", " ")
        .replaceAll("   ", " ")
        .replaceAll("“ ", "“")
        .replaceAll(" ”", "”")
        // (removed two lines here)
        .replaceAll(/(^|[-\u2014\s(\["])'/g, "$1\u2018")
        .replaceAll(/'/g, "\u2019")
        .replaceAll(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c")
        .replaceAll(/"/g, "\u201d")
        // added:
        .replace(/[“”‘]|’(?!s)/g, m => 
             "“‘".includes(m) ? "“‘"[depth++] : "”’"[--depth])
};

我没有详细检查你正在做的其他替换,但是我对这两个有一些疑问:

.replaceAll(/'/g, "\u2019") 
.replaceAll(/"/g, "\u201d")

这些调用将直引号替换为卷曲的结束引号,这显然会在您没有匹配的开始引号的情况下创建结果...

我对这两个附近的另外两个替换也有类似的担忧。

【讨论】:

  • 这似乎是一个非常好的解决方案,但您能否更改它以匹配我的示例代码?我正在尝试混合它,但由于某种原因它失败了。我真的很想试试这个。 (不太擅长 javascript)
  • 刚刚添加到我的答案中。
  • 太棒了!它适用于我现在尝试的任何样本。我也不确定这两个,但它可以帮助我通过弯引号自动修复直引号。如果我尝试删除它们,它不会得到修复。我当前脚本遇到的唯一问题是,如果单词和右引号之间有空格,它会变成开引号。 (例如“这个结束引号将变成一个开始引号,因为它前面有一个空格。”
【解决方案3】:

试试这个:

console.log("“Here’s some extra text at the beginning “abc” and at the end”"
  .replace(/(“.*?)“(.*?)”(.*”)/, "$1‘$2’$3"));

regex101 的示例

【讨论】:

  • 现在尝试使用在这些引号内包含两个或多个引号单词的字符串的正则表达式。您可能希望循环替换,直到没有匹配发生。
  • @WiktorStribiżew 是的,考虑到这一点。
猜你喜欢
  • 1970-01-01
  • 2019-03-16
  • 2021-08-12
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
相关资源
最近更新 更多