替换引号内的空格

我真的在这里与正则表达式斗争。 使用Java我将如何用另一个字符(或转义空格"\ " )替换引号内的所有空格(实际上是双引号),但仅限于短语以通配符结尾。

 word1 AND "word2 word3 word4*" OR "word5 word6" OR word7 

 word1 AND "word2\ word3\ word4*" OR "word5 word6" OR word7 

我认为最好的解决方案是使用正则表达式来查找所需的引用字符串,然后替换正则表达式匹配中的空格。 像这样的东西:

 import java.util.regex.*; class SOReplaceSpacesInQuotes { public static void main(String[] args) { Pattern findQuotes = Pattern.compile("\"[^\"]+\\*\""); for (String arg : args) { Matcher m = findQuotes.matcher(arg); StringBuffer result = new StringBuffer(); while (m.find()) m.appendReplacement(result, m.group().replace(" ", "\\\\ ")); m.appendTail(result); System.out.println(arg + " -> " + result.toString()); } } } 

运行java SOReplaceSpacesInQuotes 'word1 AND "word2 word3 word4*" OR "word5 word6*" OR word7'然后愉快地产生输出word1 AND "word2 word3 word4*" OR "word5 word6*" OR word7 -> word1 AND "word2\ word3\ word4*" OR "word5\ word6*" OR word7 ,这正是你想要的。

模式是"[^"]+\*" ,但是必须为Java转义反斜杠和引号。这匹配文字引号,任意数量的非引号, *和引号,这是您想要的。这假定(a)不允许嵌入\"转义序列,(b) *是唯一的通配符。 如果你有嵌入的转义序列,那么使用"([^\\"]|\\.)\*" (对于Java,转义为\"([^\\\\\\"]|\\\\.)\\*\" ); 如果您有多个通配符,请使用"[^"]+[*+]" ;如果您同时使用它们,请以明显的方式将它们组合在一起。处理多个通配符只需让它们中的任何一个匹配字符串;处理转义序列是通过匹配引号,后跟任意数量的非反斜杠,非引号字符任何前面的反斜杠来完成的。

现在,该模式找到您想要的引用字符串。 对于程序的每个参数,我们然后匹配所有这些参数,并使用m.group().replace(" ", "\\\\ ") ,用反斜杠替换匹配的内容(引用的字符串)中的每个空格和一个空间。 (这个字符串是\\为什么需要两个真正的反斜杠,我不确定。)如果你之前没有见过appendReplacementappendTail (我没有),这就是他们所做的:串联,他们遍历整个字符串,将与第二个参数匹配的内容替换为appendReplacement ,并将其全部附加到给定的StringBufferappendTail调用是必要的,以捕获最后不匹配的内容。 Matcher.appendReplacement(StringBuffer,String)的文档包含了一个很好的使用示例。


编辑:正如Roland Illig所指出的,如果出现某些类型的无效输入,例如a AND "b" AND *"c" ,这将成为a AND "b"\ AND\ *"c" ,这是有问题的。 如果这是一个危险(或者它可能在将来可能成为危险,它可能会成为危险),那么你应该通过始终匹配引号使其更加健壮,但只有在它们以通配符结束时才替换。 只要您的报价始终适当配对,这将是有效的,这是一个非常弱的假设。 结果代码非常相似:

 import java.util.regex.*; class SOReplaceSpacesInQuotes { public static void main(String[] args) { Pattern findQuotes = Pattern.compile("\"[^\"]+?(\\*)?\""); for (String arg : args) { Matcher m = findQuotes.matcher(arg); StringBuffer result = new StringBuffer(); while (m.find()) { if (m.group(1) == null) m.appendReplacement(result, m.group()); else m.appendReplacement(result, m.group().replace(" ", "\\\\ ")); } m.appendTail(result); System.out.println(arg + " -> " + result.toString()); } } } 

我们将通配符放在一个组中,并使其成为可选项,并使引号的主体不愿意用+? ,以便它尽可能地匹配并让通配符被分组。 这样,我们匹配每对连续的引号,并且因为正则表达式引擎不会在匹配中间重新启动,所以我们只会匹配引号的内部而不是外部。 但是现在我们并不总是想要替换空格 – 如果有通配符我们只想这样做。 这很简单:测试组1是否为null 。 如果是,则没有通配符,因此请将该字符串替换为自身。 否则,请替换空格。 事实上, java SOReplaceSpacesInQuotes 'a AND "bd" AND *"cd"'产生所需a AND "bd" AND *"cd" -> a AND "bd" AND *"cd" ,而java SOReplaceSpacesInQuotes 'a AND "bd" AND "cd*"'执行替换以获得a AND "bd" AND *"cd" -> a AND "bd" AND "c\ *d"

你真的需要正则表达式吗? 这个任务似乎很好描述,但对于正则表达式来说有点过于复杂。 所以我宁愿明确地编程出来。

 package so4478038; import static org.junit.Assert.*; import org.junit.Test; public class QuoteSpaces { public static String escapeSpacesInQuotes(String input) { StringBuilder sb = new StringBuilder(); StringBuilder quotedWord = new StringBuilder(); boolean inQuotes = false; for (int i = 0, imax = input.length(); i < imax; i++) { char c = input.charAt(i); if (c == '"') { if (!inQuotes) { quotedWord.setLength(0); } else { String qw = quotedWord.toString(); if (qw.endsWith("*")) { sb.append(qw.replace(" ", "\\ ")); } else { sb.append(qw); } } inQuotes = !inQuotes; } if (inQuotes) { quotedWord.append(c); } else { sb.append(c); } } return sb.toString(); } @Test public void test() { assertEquals("word1 AND \"word2\\ word3\\ word4*\" OR \"word5 word6\" OR word7", escapeSpacesInQuotes("word1 AND \"word2 word3 word4*\" OR \"word5 word6\" OR word7")); } } 

它有用吗?

 str.replaceAll("\"", "\\"); 

我现在没有IDE而且我没有测试它