【问题标题】:Escape special characters in a text when text is either enclosed in double quotes or not当文本被双引号括起来或没有时,转义文本中的特殊字符
【发布时间】:2016-02-15 09:23:20
【问题描述】:

我正在编写一个正则表达式来转义一些特殊字符,包括输入中的双引号。

输入可以用双引号括起来,并且不应转义。

输入示例:

"te(st", te(st, te"st 

预期输出:

"te\(st", te\(st, te\"st

使用的代码:

String regex = "^\".*\"$";
    String value = "\"strin'g\"";
    Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[()'"\\[\\]*]");

    if (Pattern.matches(regex, value)){
        String val = value.substring(1, value.length() -1);
        String replaceAll = SPECIAL_REGEX_CHARS.matcher(val).replaceAll("\\\\$0");
        replaceAll = "\""+replaceAll+"\"";
        System.out.println(replaceAll);
    }else {
        String replaceAll = SPECIAL_REGEX_CHARS.matcher(value).replaceAll("\\\\$0");
        System.out.println(replaceAll);
    }

1 - 检查文本是否用双引号括起来。如果是,请转义文本中用双引号括起来的特殊字符。

2 - 否则。转义文本中的特殊字符。

任何可以结合#1和#2的正则表达式?

问候, 阿尼尔

【问题讨论】:

  • 可以使用 1 个正则表达式的代码来完成。尽管如此,它仍需要一些额外的代码。
  • 第三行无法编译。
  • 能否请您分享正则表达式,使用条件正则表达式?我想试试这是更好的方法。不确定我的方法是否是标准方法。
  • 尝试模式 SPECIAL_REGEX_CHARS = Pattern.compile("[()\"'\[\]*]");
  • 你不希望 \ 也被转义吗?

标签: java regex


【解决方案1】:

只有一个转义正则表达式的简单解决方案

您可以使用if (s.startsWith("\"") && s.endsWith("\"")) 来检查一个字符串是否有前导和尾随",如果有,您可以使用replaceAll("^\"|\"$", "") 修剪前导和尾随",然后使用您的转义转义正则表达式,然后添加 " 回来。否则,只需转义集合中的角色即可。

String SPECIAL_REGEX_CHARS = "[()'\"\\[\\]*]";
String s = "\"te(st\""; // => "te\(st"
String result;
if (s.startsWith("\"") && s.endsWith("\"")) {
    result = "\"" + s.replaceAll("^\"|\"$", "").replaceAll(SPECIAL_REGEX_CHARS, "\\\\$0") + "\"";
}
else {
    result = s.replaceAll(SPECIAL_REGEX_CHARS, "\\\\$0");
}
System.out.println(result.toString());

查看另一个IDEONE demo

appendReplacement“回调”的替代解决方案

以下是我将如何使用一个正则表达式使用交替:

String SPECIAL_REGEX_CHARS = "[()'\"\\[\\]*]";
//String s = "\"te(st\""; // => "te\(st"
//String s = "te(st"; // => te\(st
String s = "te\"st"; // => te\"st
StringBuffer result = new StringBuffer();
Matcher m = Pattern.compile("(?s)\"(.*)\"|(.*)").matcher(s);
if (m.matches()) {
    if (m.group(1) == null) { // we have no quotes around
        m.appendReplacement(result, m.group(2).replaceAll(SPECIAL_REGEX_CHARS, "\\\\\\\\$0"));
    }
    else {
        m.appendReplacement(result, "\"" + m.group(1).replaceAll(SPECIAL_REGEX_CHARS, "\\\\\\\\$0") + "\"");
    }
}
m.appendTail(result);
System.out.println(result.toString());

IDEONE demo

要点:

  • Matcher#addReplacement()Matcher#appendTail() 允许操作组。
  • 使用(?s)\"(.*)\"|(.*) 正则表达式和2 个替代分支:".*" 匹配以" 开头并以" 结尾的字符串(注意(?s) 是一个DOTALL 内联修饰符,允许将字符串与换行符序列匹配)或.* 替代只是匹配所有其他字符串。
  • 如果匹配到第一个选项,我们只需替换第一个捕获组中选择的特殊字符,然后在两端添加"
  • 如果匹配第二个选项,只需在整个 Group 2 中添加转义符号即可。
  • 要替换为文字反斜杠,您需要在替换模式中使用\\\\\\\\

【讨论】:

  • 您知道,“简化”对于不同的人可能意味着不同的东西 :) 考虑到您的要求,我认为这已经很简单了。如果有任何不清楚的地方,请询问。
  • 我添加了一个“更简单”的解决方案,使用最少的正则表达式。
【解决方案2】:

您可以使用negative lookbehind and lookahead

System.out.println(value.replaceAll("([()'\\[\\]*]|(?<!^)\"(?!$))", "\\\\$0"));

这实质上是说:转义字符类 [()'\[\]*] 或任何 " 前面没有字符串开头或后面没有字符串结尾的任何内容。

唯一的问题是,无论在另一端是否有相应的引号,前导引号和尾随引号都将被忽略。如果这是一个问题,您可以将这些替换链接起来以转义不匹配的前导或尾随引号:

.replaceAll("^\".*[^\"]$", "\\\\$0")
.replaceAll("(^[^\"].*)(\"$)", "$1\\\\$2")

【讨论】:

  • 环视方法的问题在于,这样一来,无法检查输入是否在字符串的开头 结尾都有"
  • @AnilDasari,我收到了"\(te\"st"。你期待别的吗?
  • @WiktorStribiżew 这取决于他在检查匹配引号方面的特殊程度。据我所知,这个输入不可能有不匹配的引号。
  • 好吧,无论如何,我相信检查一个字符串是否以双引号开头或结尾,我们真的不需要正则表达式。
猜你喜欢
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-10
  • 2016-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
相关资源
最近更新 更多