【问题标题】:Splitting string on spaces unless in double quotes but double quotes can have a preceding string attached除非在双引号中,否则在空格上拆分字符串,但双引号可以附加前面的字符串
【发布时间】:2018-05-03 09:20:57
【问题描述】:

我需要在 Java 中拆分一个字符串(首先删除引号之间的空格,然后在空格处拆分。)

"abc test=\"x y z\"magic=\"你好\"hola"

变成:

首先:

"abc test=\"xyz\" magic=\"hello\" hola"

然后:

  • abc
  • test="xyz"
  • magic="你好"
  • 你好

场景: 我从输入中得到一个类似上面的字符串,我想把它分成上面的部分。一种方法是首先删除引号之间的空格,然后在空格处拆分。引号前的字符串也使其复杂化。第二个在空格处拆分,但如果在引号内则不拆分,然后从单个拆分中删除空格。我尝试使用 "\"([^\"]+)\"" 捕获引号,但我无法仅捕获引号内的空格。我尝试了更多但没有运气。

【问题讨论】:

  • 你本质上是想写一个解析器。然后以您想要的任何格式输出数据。正则表达式本身可能不是适合您的解决方案。你能告诉我们你尝试了什么,以及目标是什么(你为什么这样做)
  • 你可以试试System.out.println("abc test=\"x y z\" magic=\" hello \" hola".replace(" ", ",\n"));

标签: java regex split


【解决方案1】:

我们可以使用正式的模式匹配器来做到这一点。下面答案的秘诀是使用不常用的Matcher#appendReplacement 方法。我们在每场比赛中暂停,然后附加一个自定义替换出现在两对引号内的任何内容。自定义方法 removeSpaces() 会从每个引用的术语中去除所有空格。

public static String removeSpaces(String input) {
    return input.replaceAll("\\s+", "");
}

String input = "abc test=\"x y z\" magic=\" hello \" hola";
Pattern p = Pattern.compile("\"(.*?)\"");
Matcher m = p.matcher(input);
StringBuffer sb = new StringBuffer("");
while (m.find()) {
    m.appendReplacement(sb, "\"" + removeSpaces(m.group(1)) + "\"");
}
m.appendTail(sb);

String[] parts = sb.toString().split("\\s+");
for (String part : parts) {
    System.out.println(part);
}

abc
test="xyz"
magic="hello"
hola

Demo

正如上面的 cmets 所暗示的那样,这里最大的警告是,我们实际上是在使用正则表达式引擎作为基本的解析器。要查看我的解决方案在哪里快速失败,只需从引用的术语中意外删除其中一个引号。但是,如果您确定您的输入格式正确,正如您向我们展示的那样,这个答案可能对您有用。

【讨论】:

  • 不错的答案!。从来不知道“模式”。
【解决方案2】:

我想提一下 java 9 的 Matcher.replaceAll lambda 扩展:

// Find quoted strings and remove there whitespace:
s = Pattern.compile("\"[^\"]*\"").matcher(s)
    .replaceAll(mr -> mr.group().replaceAll("\\s", ""));

// Turn the remaining whitespace in a comma and brace all.
s = '{' + s.trim().replaceAll("\\s+", ", ") + '}';

【讨论】:

    【解决方案3】:

    可能另一个答案更好,但我仍然写了它,所以我会在这里发布;)它采用不同的方法

    public static void main(String[] args) {
            String test="abc test=\"x y z\"   magic=\"  hello   \"   hola";
              Pattern pattern = Pattern.compile("([^\\\"]+=\\\"[^\\\"]+\\\" )");
                Matcher matcher = pattern.matcher(test);
                int lastIndex=0;
                while(matcher.find()) {
                    String[] parts=matcher.group(0).trim().split("=");
    
                    boolean newLine=false;
                    for (String string : parts[0].split("\\s+")) {
                        if(newLine)
                            System.out.println();
                        newLine=true;
                        System.out.print(string);
                    }
                    System.out.println("="+parts[1].replaceAll("\\s",""));
                    lastIndex=matcher.end();
                }
                System.out.println(test.substring(lastIndex).trim());           
        }
    

    结果是

    abc
    test="xyz"
    magic="hello"
    hola
    

    【讨论】:

      【解决方案4】:

      听起来您想编写一个基本的解析器/标记器。我敢打赌,当你在这个结构中做出可以处理漂亮打印的东西之后,你很快就会开始验证没有任何不匹配的"'s。

      但本质上,这个特定问题有几个阶段,Java 有一个内置的标记器,可以证明是有用的。

      import java.util.LinkedList;
      import java.util.List;
      import java.util.StringTokenizer;
      import java.util.stream.Collectors;
      
      public class Q50151376{
      
          private static class Whitespace{
              Whitespace(){ }
              @Override
              public String toString() {
                  return "\n";
              }
          }
      
          private static class QuotedString {
              public final String string;
      
              QuotedString(String string) {
                  this.string = "\"" + string.trim() + "\"";
              }
      
              @Override
              public String toString() {
                  return string;
              }
          }
      
          public static void main(String[] args) {
              String test = "abc test=\"x y z\" magic=\" hello \" hola";
              StringTokenizer tokenizer = new StringTokenizer(test, "\"");
              boolean inQuotes = false;
              List<Object> out = new LinkedList<>();
              while (tokenizer.hasMoreTokens()) {
                  final String token = tokenizer.nextToken();
                  if (inQuotes) {
                      out.add(new QuotedString(token));
                  } else {
                      out.addAll(TokenizeWhitespace(token));
                  }
                  inQuotes = !inQuotes;
              }
      
              System.out.println(joinAsStrings(out));
          }
      
          private static String joinAsStrings(List<Object> out) {
              return out.stream()
                      .map(Object::toString)
                      .collect(Collectors.joining());
          }
      
          public static List<Object> TokenizeWhitespace(String in){
              List<Object> out = new LinkedList<>();
              StringTokenizer tokenizer = new StringTokenizer(in, " ", true);
      
              boolean ignoreWhitespace = false;
              while (tokenizer.hasMoreTokens()){
                  String token = tokenizer.nextToken();
                  boolean whitespace = token.equals(" ");
                  if(!whitespace){
                      out.add(token);
                      ignoreWhitespace = false;
                  } else if(!ignoreWhitespace) {
                      out.add(new Whitespace());
                      ignoreWhitespace = true;
                  }
              }
              return out;
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-19
        • 2020-11-06
        • 2018-10-26
        • 2011-12-25
        相关资源
        最近更新 更多