Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 逗号外引号上的拆分_Java_Regex_String_Split - Fatal编程技术网

Java 逗号外引号上的拆分

Java 逗号外引号上的拆分,java,regex,string,split,Java,Regex,String,Split,我的程序从文件中读取一行。此行包含逗号分隔的文本,如: 123,test,444,"don't split, this",more test,1 我希望拆分的结果如下: 123 test 444 "don't split, this" more test 1 如果我使用字符串.split(“,”,我将得到以下结果: 123 test 444 "don't split this" more test 1 换句话说:子字符串中的逗号“不拆分,此”不是分隔符。如何处理此问题?您可以试用此正则表

我的程序从文件中读取一行。此行包含逗号分隔的文本,如:

123,test,444,"don't split, this",more test,1
我希望拆分的结果如下:

123
test
444
"don't split, this"
more test
1
如果我使用
字符串.split(“,”
,我将得到以下结果:

123
test
444
"don't split
 this"
more test
1

换句话说:子字符串
中的逗号“不拆分,此”
不是分隔符。如何处理此问题?

您可以试用此正则表达式:

str.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
这将拆分
上的字符串,该字符串后跟偶数个双引号。换句话说,它在双引号外以逗号分隔。如果字符串中有平衡的引号,这将起作用

说明:

,           // Split on comma
(?=         // Followed by
   (?:      // Start a non-capture group
     [^"]*  // 0 or more non-quote characters
     "      // 1 quote
     [^"]*  // 0 or more non-quote characters
     "      // 1 quote
   )*       // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
   [^"]*    // Finally 0 or more non-quotes
   $        // Till the end  (This is necessary, else every comma will satisfy the condition)
)
您甚至可以在代码中键入这样的内容,在正则表达式中使用
(?x)
修饰符。修饰符会忽略正则表达式中的任何空格,因此更容易阅读分成多行的正则表达式,如下所示:

String[] arr = str.split("(?x)   " + 
                     ",          " +   // Split on comma
                     "(?=        " +   // Followed by
                     "  (?:      " +   // Start a non-capture group
                     "    [^\"]* " +   // 0 or more non-quote characters
                     "    \"     " +   // 1 quote
                     "    [^\"]* " +   // 0 or more non-quote characters
                     "    \"     " +   // 1 quote
                     "  )*       " +   // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
                     "  [^\"]*   " +   // Finally 0 or more non-quotes
                     "  $        " +   // Till the end  (This is necessary, else every comma will satisfy the condition)
                     ")          "     // End look-ahead
                         );

无需复杂的正则表达式,即可轻松完成此操作:

  • 在字符
    上拆分。您将得到一个字符串列表
  • 处理列表中的每个字符串:在“,”上拆分列表中处于偶数位置的每个字符串(以零开始索引)(您在列表中得到一个列表),单独保留每个奇数位置的字符串(直接将其放入列表中)
  • 加入列表列表,这样您只会得到一个列表
  • 如果您想处理对''的引用,您必须稍微调整算法(加入一些部分,您错误地拆分了,或者将拆分更改为简单的regexp),但基本结构保持不变

    所以基本上是这样的:

    public class SplitTest {
        public static void main(String[] args) {
            final String splitMe="123,test,444,\"don't split, this\",more test,1";
            final String[] splitByQuote=splitMe.split("\"");
            final String[][] splitByComma=new String[splitByQuote.length][];
            for(int i=0;i<splitByQuote.length;i++) {
                String part=splitByQuote[i];
                if (i % 2 == 0){
                   splitByComma[i]=part.split(",");
                }else{
                    splitByComma[i]=new String[1];
                    splitByComma[i][0]=part;
                }
            }
            for (String parts[] : splitByComma) {
                for (String part : parts) {
                    System.out.println(part);
                }
            }
        }
    }
    
    公共类拆分测试{
    公共静态void main(字符串[]args){
    最后一个字符串splitMe=“123,test,444,\“不要拆分,这个\”,更多测试,1”;
    最后一个字符串[]splitByQuote=splitMe.split(“\”);
    最终字符串[][]splitByComma=新字符串[splitByQuote.length]];
    
    对于(int i=0;i请参见下面的代码段。此代码仅考虑快乐流。根据您的要求更改

    public static String[] splitWithEscape(final String str, char split,
            char escapeCharacter) {
        final List<String> list = new LinkedList<String>();
    
        char[] cArr = str.toCharArray();
    
        boolean isEscape = false;
        StringBuilder sb = new StringBuilder();
    
        for (char c : cArr) {
            if (isEscape && c != escapeCharacter) {
                sb.append(c);
            } else if (c != split && c != escapeCharacter) {
                sb.append(c);
            } else if (c == escapeCharacter) {
                if (!isEscape) {
                    isEscape = true;
                    if (sb.length() > 0) {
                        list.add(sb.toString());
                        sb = new StringBuilder();
                    }
                } else {
                    isEscape = false;
                }
    
            } else if (c == split) {
                list.add(sb.toString());
                sb = new StringBuilder();
            }
        }
    
        if (sb.length() > 0) {
            list.add(sb.toString());
        }
    
        String[] strArr = new String[list.size()];
    
        return list.toArray(strArr);
    }
    
    publicstaticstring[]splitWithEscape(最终字符串str,charsplit,
    字符(字符){
    最终列表=新的LinkedList();
    char[]cArr=str.toCharArray();
    布尔isEscape=false;
    StringBuilder sb=新的StringBuilder();
    用于(字符c:cArr){
    if(isEscape&&c!=转义字符){
    sb.附加(c);
    }else if(c!=split&&c!=escapeCharacter){
    sb.附加(c);
    }else if(c==转义字符){
    如果(!isEscape){
    isEscape=真;
    如果(sb.length()>0){
    添加(sb.toString());
    sb=新的StringBuilder();
    }
    }否则{
    isEscape=假;
    }
    }如果(c==split),则为else{
    添加(sb.toString());
    sb=新的StringBuilder();
    }
    }
    如果(sb.length()>0){
    添加(sb.toString());
    }
    String[]strArr=新字符串[list.size()];
    返回列表。toArray(strArr);
    }
    
    如果可以匹配,为什么要拆分?

    由于某种原因,没有提到简单的解决方案,因此重新提出了这个问题。这是我们的漂亮紧凑的正则表达式:

    "[^"]*"|[^,]+
    
    这将匹配所有需要的片段()

    解释

    • 使用
      “[^”]*”
      ,我们匹配完整的
      “双引号字符串”
    • |
    • 我们匹配任何非逗号的字符

    一种可能的改进是改进替换的字符串端,以允许引用的字符串包含转义引号。

    基于@zx81的答案,因为匹配的想法非常好,我添加了Java 9
    调用,它返回一个
    。因为OP想要使用
    spl它
    ,我已经收集到
    String[]
    ,就像
    split
    一样

    注意:如果逗号分隔符(
    a,b,“c,d”)后面有空格,则需要更改模式。

    Jshell演示 解释
  • Regex
    [^”]
    匹配:一个引号,除引号外的任何内容,一个引号
  • Regex
    [^”]*
    匹配:一个引号,除引号0(或更多)次外的任何内容,一个引号
  • 该正则表达式需要首先进入“win”,否则匹配除逗号以外的任何内容1次或多次,即:
    [^,]+
    -将“win”
  • results()
    需要Java 9或更高版本
  • 它返回
    Stream
    ,我使用
    group()
    调用和collect将其映射到字符串数组。无参数
    toArray()
    调用将返回
    Object[]

  • 为什么这是一个要求?你能提供更多关于你试图解决的问题的信息吗?这些年来,这个答案仍然很有价值!让我的程序与你的解释一起工作。谢谢!现在,有什么方法可以添加换行符吗?\n和\r?嗨,我的字符串是这样的:\“不要拆分,这个\”(它前面有那些反斜杠。)如何修改正则表达式呢?嗨,Rohit,我遵循了你的解决方案,我有两个分隔符,和/或。并在正则表达式后面使用:(\s+和\s+)\s+或\s+(=(?:[^\“]*”[^\“]*”[^\“]*”[^\“]*$)。它对大多数用例都很有效,但输入失败:'brand=='Kellogg\'s'或country='UnitedStates和“India\”。你能帮帮我吗?我对regex很陌生。这不适用于非普通情况,例如,如果文本本身包含引号,则需要转义,如
    \“
    因为我更喜欢这个,而不是拆分,所以我将它与Matcher中的Java 9改进结合起来,允许流式处理。我的答案包含jshell会话演示它。如果您还需要获取空字符串,这个解决方案将不起作用,但我喜欢它。@zx81您知道如何使用转义引号\”使它起作用吗?”?
    $ jshell
    -> String so = "123,test,444,\"don't split, this\",more test,1";
    |  Added variable so of type String with initial value "123,test,444,"don't split, this",more test,1"
    
    -> Pattern.compile("\"[^\"]*\"|[^,]+").matcher(so).results();
    |  Expression value is: java.util.stream.ReferencePipeline$Head@2038ae61
    |    assigned to temporary variable $68 of type java.util.stream.Stream<MatchResult>
    
    -> $68.map(MatchResult::group).toArray(String[]::new);
    |  Expression value is: [Ljava.lang.String;@6b09bb57
    |    assigned to temporary variable $69 of type String[]
    
    -> Arrays.stream($69).forEach(System.out::println);
    123
    test
    444
    "don't split, this"
    more test
    1
    
    String so = "123,test,444,\"don't split, this\",more test,1";
    Pattern.compile("\"[^\"]*\"|[^,]+")
        .matcher(so)
        .results()
        .map(MatchResult::group)
        .toArray(String[]::new);