替换引号内的空格

时间:2010-12-18 12:35:50

标签: java regex

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

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

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

3 个答案:

答案 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(" ", "\\\\ "),用匹配(带引号的字符串)替换反斜杠和空格中的每个空格。 (这个字符串是\\ - 为什么需要两个真正的反斜杠,我不确定。)如果你之前没有见过appendReplacementappendTail(我没有),这里是他们做了什么:串联,他们遍历整个字符串,将第二个参数匹配的任何内容替换为appendReplacement,然后将其全部附加到给定的StringBufferappendTail调用是必要的,以捕获最后不匹配的内容。 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而且我没有测试它