【问题标题】:Replace quotes (but not touch nested quotes)替换引号(但不触及嵌套引号)
【发布时间】:2019-10-10 10:12:47
【问题描述】:

下期遇到问题: 我需要用角度引号替换引号,但如果句子再次得到引号 - 不应该被替换。

为了获得公开报价,我接下来使用:

const regexStartQuote = /"(?=\S)/gm;
const replaceStartQuote = '«'

用我使用的结尾替换引号:

// const regexEndQuote = /(?<=\S)"/gm; // not supported in Mozilla
const regexEndQuote = /"(?=\s)/gm;
const replaceEndQuote = '»'

这很有效。我是说: “一些文字” -> «一些文字»

顺便说一句,我使用的是 Draftjs,并且这些更改是即时应用的。

我需要扩展现有的正则表达式,所以如果句子应该是这样的:

«一些文本“引号中的文本”更多»

当然还有可能的变体,例如:

«一些文本“引号中的文本”,还有更多»

«一些文字:“引号中的文字”,还有更多»

«一些文字:“引号中的文字”,- 更多»

更新

接下来是程序流程: 键入的每个符号都与字符串合并。我的意思是,首先当例如文本块为空

字符串只是``(空),

然后用户输入'w' -> 字符串变成w,

然后是'o' -> 字符串wo,

那么'w' -> 字符串是wow,

那么 ' ' (空格) -> 字符串是wow,

那么" -> 字符串是wow «

等等

据我了解,正则表达式应该类似于:

`如果用户键入“并且在它之前没有»,但我们有«我们不应该更改”。

【问题讨论】:

  • 当用户打字时,这似乎太复杂了(不可能?)。当用户结束输入时,您最好检查/替换整个字符串。

标签: javascript regex


【解决方案1】:

这处理出现在行边界上的引用字符串的嵌套(引用字符串本身不必开始结束开始 em> 和 end 行)。这有点人为,但是如果您想在外部引用字符串中允许多个内部引用字符串,那么这几乎成为必需品。这将是问题所在。考虑以下字符串:

var s = '"This is an "internal quote" within a sentence." A short sentence.\n' +
        '"Another quoted sentence."\n' +
        '"Yet another quoted sentence."' +
        'etc.';

例如,是什么阻止了" A short sentence.\n""\n" 被识别为内部带引号的字符串?换句话说,当引号表示外部引用字符串的结束或新的内部引用字符串的开始时(至少在您到达整个输入的结尾之前)变得不可能。

正则表达式:^([^"\n]*)"((?:[^"\n]*"[^"\n]*")*[^"\n]*)"([^*\n]*)$

  1. ^ 匹配行首。
  2. ([^"\n]*) 捕获组 1:0 个或更多字符与 " 或换行符以外的任何字符匹配。这是可能在开头引号之前的所有内容。
  3. " 匹配开场白。现在我们将寻找带有外部引号的可选引号字符串
  4. (?:[^"\n]*"[^"\n]*") 一个非捕获组,它查找 0 个或多个非引号/非换行符后跟一个引号,然后是 0 个或多个非引号/非换行符,后跟一个引号。这将是一个内部引用的字符串。
  5. ((?:[^"\n]*"[^"\n]*"))*上述模式可以重复0次或多次。
  6. [^"\n]*" 匹配 0 个或多个非引号/非换行符后跟引号。这负责匹配引用字符串的其余部分。
  7. ([^*\n]*) 匹配行的其余部分(0 个或多个字符),不应包含引号。

上面的正则表达式相当复杂,因为它检查平衡的引号。如果您不关心进行这种严格的检查,那么只查找一行中的第一个和最后一个引号的更简单的正则表达式将是(并且其余代码保持不变):

/^([^"\n]*)"([^\n]*)"([^"\n])*$/gm;

var s = 'A plain line.\n' +
        'This is "Some text in quotes" and some without.\n' +
        '"This has "quotes within quotes" and some without."\n' +
        '"This has "many" "quoted" "strings" within quotes."'
        ;

var regex = /^([^"\n]*)"((?:[^"\n]*"[^"\n]*")*[^"\n]*)"([^*\n]*)$/gm;
console.log(s.replace(regex, "$1«$2»$3"));

更新

要修改输入 s,在输入时,您需要针对几个正则表达式进行测试:

  1. 如果输入与 /^[^"\n]*$/ 匹配(行中没有引号),则无需替换。
  2. 如果输入匹配/^[^«\n]*«([^»\n]*»)?[^"\n]*$/,则无需替换。
  3. 如果输入匹配/^([^"«\n]*)"$/(看到第一个引号),那么s = s.replace('"', '«');
  4. 如果输入匹配/^([^"«\n]*)«([^\n]*)"$/(除了看到的第一个引号),那么s = s.replace('»', '"'); s = s.replace(/"$/, '»');

代码 sn-ps 似乎不允许真正的一次输入一个字符,但这个模拟了它的样子:

function test(str)
{
    let s = '';
    for (let i = 0; i < str.length; i++) {
        key = str.charAt(i);

        s += key;
        if (/^[^"\n]*$/.test(s) || /^[^«\n]*«([^»\n]*»)?[^"\n]*$/.test(s))
            ;
        else if (/^([^"«\n]*)"$/.test(s))
            s = s.replace('"', '«');
        else if (/^([^"«\n]*)«([^\n]*)"$/.test(s)) {
            s = s.replace('»', '"');
            s = s.replace(/"$/, '»');
        }
       console.log("\n" + s);
    }

}

test('a"bc"de"fg"h"ij"');

【讨论】:

  • 谢谢,通过添加执行流程更新问题。
  • 感谢您的回答..结果总是变化的主要问题..在更新中我尝试解释流程
  • @WannaBeBetter 我不确定你还想要什么。我还添加了一个不那么严格的更简单的正则表达式(它接受不平衡的引号,例如"This is "unbalanced.")。
  • @WannaBeBetter 我已经展示了如何处理一次一个字符的输入。我完成了
【解决方案2】:

试试这个解决方案

const startRegex = /^"/gm;
const endRegex = /"$/gm;

str.replace(startRegex, "<<")

str.replace(endRegex, ">>")

const startRegex = /^"/gm;
const endRegex = /"$/gm;
const str = `"Some text "Text in quotes" something more"`

let result = str.replace(startRegex, "<<")
result = result.replace(endRegex, ">>")

console.log(result);

【讨论】:

  • 感谢您的回答,但闭角报价存在问题:«text "dsf" adsfsdfdsf"
  • 如果在线应用的更改 $ 似乎无法使用,因为 ;字面上你总是在字符串的末尾...
  • 能否请您添加一些示例字符串。
  • 谢谢,通过添加执行流程更新问题。
猜你喜欢
  • 1970-01-01
  • 2019-03-16
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 2018-09-23
  • 2019-08-31
  • 2019-01-21
相关资源
最近更新 更多