我真的在这里与正则表达式斗争。使用Java我如何用另一个字符(或转义空格"\ "
)替换引号内的所有空格(实际上是双引号),但只有当短语以通配符结束时才会这样。
word1 AND "word2 word3 word4*" OR "word5 word6" OR word7
到
word1 AND "word2\ word3\ word4*" OR "word5 word6" OR word7
答案 0 :(得分:2)
你真的需要正则表达吗?这个任务似乎很好描述,但对于正则表达式来说有点过于复杂。所以我宁愿明确地编程。
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"));
}
}
答案 1 :(得分:2)
我认为最好的解决方案是使用正则表达式查找所需的引用字符串,然后替换正则表达式匹配中的空格。像这样:
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(" ", "\\\\ ")
,用匹配(带引号的字符串)替换反斜杠和空格中的每个空格。 (这个字符串是\\
- 为什么需要两个真正的反斜杠,我不确定。)如果你之前没有见过appendReplacement
和appendTail
(我没有),这里是他们做了什么:串联,他们遍历整个字符串,将第二个参数匹配的任何内容替换为appendReplacement
,然后将其全部附加到给定的StringBuffer
。 appendTail
调用是必要的,以捕获最后不匹配的内容。 documentation for 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());
}
}
}
我们将通配符放在一个组中,并使其成为可选项,并使引号的主体对+?
不情愿,以便它尽可能匹配 little 并让通配符被分组。这样,我们匹配每对连续的引号,并且因为正则表达式引擎不会在匹配中间重新启动,所以我们只会匹配引号的内部而不是外部。但是现在我们并不总是想要替换空格 - 如果有通配符,我们只想这样做。这很简单:测试组1是null
。如果是,那么就没有通配符,所以用自己替换字符串。否则,请替换空格。事实上,java SOReplaceSpacesInQuotes 'a AND "b d" AND *"c d"'
会产生所需的a AND "b d" AND *"c d" -> a AND "b d" AND *"c d"
,而java SOReplaceSpacesInQuotes 'a AND "b d" AND "c d*"'
会执行替换以获得a AND "b d" AND *"c d" -> a AND "b d" AND "c\ *d"
。
答案 2 :(得分:-1)
有用吗?
str.replaceAll("\"", "\\");
我现在没有IDE而且我没有测试它