拆分逗号分隔字符串,忽略引号中的逗号,但允许带有一个双引号的字符串

时间:2011-05-11 18:16:23

标签: java regex parsing matcher

我已经在stackoverflow上搜索了几篇关于如何在逗号分隔符上拆分字符串的帖子,但忽略了引号中逗号的拆分(参见:How do I split a string into an array by comma but ignore commas inside double quotes?)我试图实现类似的结果,但还需要允许包含一个双引号的字符串。

IE。需要"test05, \"test, 05\", test\", test 05"分成

  • test05
  • "test, 05"
  • test"
  • test 05

我尝试了类似于这里提到的方法:

Regex for splitting a string using space when not surrounded by single or double quotes

使用匹配器而不是split()。但是,它的具体例子是在空格上分割,而不是在逗号上。我试图调整模式以说明逗号,但是没有运气。

String str = "test05, \"test, 05\", test\", test 05";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|([^,]+?)),++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

5 个答案:

答案 0 :(得分:1)

你已经达到正则表达式崩溃的程度。

我建议您编写一个简单的拆分器来处理您的 希望的特殊情况。测试驱动开发非常适合这样做。

但是,它看起来像是在尝试解析CSV行。您是否考虑过使用CSV库?

答案 1 :(得分:1)

我对此有类似的问题,而且我发现没有好的.net解决方案,所以去了DIY。

在我的应用程序中,我正在解析csv,因此我的拆分凭证是&#34;,&#34;。我想这个方法只适用于你有一个char split参数的地方。

所以,我编写了一个忽略双引号内逗号的函数。它通过将输入字符串转换为字符数组并通过char

解析char来实现
public static string[] Splitter_IgnoreQuotes(string stringToSplit)
    {   
        char[] CharsOfData = stringToSplit.ToCharArray();
        //enter your expected array size here or alloc.
        string[] dataArray = new string[37];
        int arrayIndex = 0;
        bool DoubleQuotesJustSeen = false;          
        foreach (char theChar in CharsOfData)
        {
            //did we just see double quotes, and no command? dont split then. you could make ',' a variable for your split parameters I'm working with a csv.
            if ((theChar != ',' || DoubleQuotesJustSeen) && theChar != '"')
            {
                dataArray[arrayIndex] = dataArray[arrayIndex] + theChar;
            }
            else if (theChar == '"')
            {
                if (DoubleQuotesJustSeen)
                {
                    DoubleQuotesJustSeen = false;
                }
                else
                {
                    DoubleQuotesJustSeen = true;
                }
            }
            else if (theChar == ',' && !DoubleQuotesJustSeen)
            {
                arrayIndex++;
            }
        }
        return dataArray;
    }

对于我的应用程序,这个函数在任何输入中都会忽略(&#34;&#34;),因为这些不需要并存在于我的输入中。

答案 2 :(得分:0)

反对这种模式:

(?<=\"?),(?!\")|(?<!\"),(?=\")

所以它将是:

String[] splitArray = subjectString.split("(?<=\"?),(?!\")|(?<!\"),(?=\")");

UPD:根据问题逻辑的最近变化,最好不要使用裸分割,首先应该用逗号分隔逗号中的文本,然后在最后一个上进行简单分割(“,”)。只需使用简单的for循环并检查你遇到多少引号,同时将你读过的字符保存到StringBuffer中。首先将字符保存到StringBuffer中,直到遇到引号,然后将StringBuffer放入包含不在引号中的字符串的数组中。然后你创建新的StringBuffer并保存你读入的下一个字符,在你遇到第二个逗号后,你停止并将你的新StringBuffer放入包含逗号字符串的数组中。重复直到字符串结束。因此,您将拥有2个数组,一个使用逗号处理的字符串,另一些字符串不是逗号。然后你应该拆分第二个数组的所有元素。

答案 3 :(得分:0)

除非你真的需要DIY,否则你应该考虑使用Apache Commons类org.apache.commons.csv.CSVParser

http://commons.apache.org/sandbox/csv/apidocs/org/apache/commons/csv/CSVParser.html

答案 4 :(得分:0)

试试这个:

import java.util.regex.*;

public class Main {
  public static void main(String[] args) throws Exception {

    String text = "test05, \"test, 05\", test\", test 05";

    Pattern p = Pattern.compile(
        "(?x)          # enable comments                                      \n" +
        "(\"[^\"]*\")  # quoted data, and store in group #1                   \n" +
        "|             # OR                                                   \n" +
        "([^,]+)       # one or more chars other than ',', and store it in #2 \n" +
        "|             # OR                                                   \n" +
        "\\s*,\\s*     # a ',' optionally surrounded by space-chars           \n"
    );

    Matcher m = p.matcher(text);

    while (m.find()) {
      // get the match
      String matched = m.group().trim();

      // only print the match if it's group #1 or #2
      if(m.group(1) != null || m.group(2) != null) {
        System.out.println(matched);
      }
    }
  }
}

对于test05, "test, 05", test", test 05,它会产生:

test05
"test, 05"
test"
test 05

并且test05, "test 05", test", test 05产生:

test05
"test 05"
test"
test 05