【问题标题】:How to split a string, keeping only certain delimiters?如何拆分字符串,只保留某些分隔符?
【发布时间】:2016-12-27 19:02:44
【问题描述】:

我有一个类似于How to split a string, but also keep the delimiters? 的问题。如何使用正则表达式拆分字符串,保留某些类型的分隔符,但不保留其他分隔符?具体来说,我想保留非空白分隔符,而不是空白分隔符。

具体化:

"a;b c"        | ["a", ";", "b", "c"]
"a; ; bb c ;d" | ["a", ";", ";", "bb", "c", ";", "d"]

这可以用正则表达式干净地完成吗?如果可以,如何?

现在我正在解决这个问题,先拆分要保留的角色,然后再拆分另一个。如果正则表达式不能这样做,或者不能干净地这样做,我可以坚持这种方法:

Arrays.stream(input.split("((?<=;)|(?=;))"))
        .flatMap(s -> Arrays.stream(s.split("\\s+")))
        .filter(s -> !s.isEmpty())
        .toArray(String[]::new); // In practice, I would generally use .collect(Collectors.toList()) instead

【问题讨论】:

    标签: java regex split regex-lookarounds


    【解决方案1】:

    我建议捕获你想要的,而不是使用这种简单的模式进行拆分

    ([^; ]+|;)
    

    Demo

    【讨论】:

    • 虽然这不能回答有关在正则表达式上拆分的问题,但这可能是构建所需元素列表的基本问题的最佳答案。它简单、简洁、易于理解且不言自明。其他解决方案需要对正则表达式有相当深入的了解,并对所使用的正则表达式进行仔细评估。但是,我不确定是否应该将其标记为已接受的答案,因为拆分列表的实际问题本身也有优点。
    • 这将是此解决方案的实际 Java 代码,在更新它以包含 \s 字符类包含的所有空格,而不仅仅是空格:Matcher matcher = Pattern.compile("([^; \t\n\u000B\f\r]+|;)").matcher(input); List&lt;String&gt; matches = new ArrayList&lt;&gt;(); while(matcher.find()) { matches.add(matcher.group()); } return matches;。请注意,实际的 Java 代码比使用 split 要长,因为 API 不提供获取所有组的单行机制。
    【解决方案2】:

    我找到了一个有效的正则表达式:

    (\\s+)|((?<=;)(?=\\S)|(?<=\\S)(?=;))
    
    public static void main(String argss[]){
        System.out.println(Arrays.toString("a; ; b c ;d"
            .split("(\\s+)|((?<=;)(?=\\S)|(?<=\\S)(?=;))")));
    }
    

    将打印出来:

    [a, ;, ;, b, c, ;, d]
    

    【讨论】:

      【解决方案3】:

      你可以这样做:

      System.out.println(String.join("-", "a; ; b c ;d".split("(?!\\G) *(?=;)|(?<=;) *| +")));
      

      详情:

      (?!\\G)  # not contiguous to a previous match and not at the start of the string
      [ ]*     # optional spaces
      (?=;)    # followed by a ;
      |    # OR
      (?<=;)   # preceded by a ;
      [ ]*     # optional spaces
      |    # OR
      [ ]+     # several spaces 
      

      随意将文字空间更改为\\s。为避免出现空项(当字符串以空格开头时在结果数组的开头),您需要先修剪字符串。

      显然,没有拆分的约束,@alphabravo 方式是最简单的。

      【讨论】:

      • 这很好,但单独"(?!\\G)\\s*" 不会成功吗?它当然适用于给出的示例。
      • @AlanMoore 我更新了示例以表明我希望多个连续的非空白、非分号字符包含在同一个匹配结果中。这种简化不适用于更新后的示例。
      【解决方案4】:

      你想在空格上分割,或者在一个字母和一个非字母之间分割:

      str.split("\\s+|(?<=\\w)(?=\\W)|(?<=\\W)(?=\\w)");
      

      【讨论】:

      • 这并不能完全回答所提出的问题,因为我实际上并不关心它是否是一个单词字符(\w 与 [\p{Alpha}\p{gc=Mn }\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}]),不管它是不是分号。上面 Arthur 的解决方案 (stackoverflow.com/a/39059565/1108305) 实际上与这个解决方案相同,但只检查分号和空格。
      【解决方案5】:

      在意识到 Java 不支持将捕获的拆分字符添加到
      拆分数组元素,我想我会尝试一个 split 解决方案而没有那个
      能力。

      基本上只有 4 种排列涉及空格和冒号。
      最后,只有空格。

      这是正则表达式。

      原始:\s+(?=;)|(?&lt;=;)\s+|(?&lt;!\s)(?=;)|(?&lt;=;)(?!\s)|\s+

      字符串:"\\s+(?=;)|(?&lt;=;)\\s+|(?&lt;!\\s)(?=;)|(?&lt;=;)(?!\\s)|\\s+"

      解释了带有排列的扩展正则表达式。
      祝你好运!

          \s+                  # Required, suck up wsp before ;
          (?= ; )              # ;
      
       |                     # or,
      
          (?<= ; )             # ;
          \s+                  # Required, suck up wsp after ;
      
       |                     # or,
      
          (?<! \s )            # No wsp before ;
          (?= ; )              # ;
      
       |                     # or,
      
          (?<= ; )             # ;
          (?! \s )             # No wsp after ;
      
       |                     # or,
      
          \s+                  # Required wsp
      

      编辑

      要在 BOS 上停止对空格的拆分,请使用此正则表达式。

      原始:\s+(?=;)|(?&lt;=;)\s+|(?&lt;!\s)(?=;)|(?&lt;=;)(?!\s)|(?&lt;!^)(?&lt;!\s)\s+

      字符串:"\\s+(?=;)|(?&lt;=;)\\s+|(?&lt;!\\s)(?=;)|(?&lt;=;)(?!\\s)|(?&lt;!^)(?&lt;!\\s)\\s+"

      解释:

          \s+                  # Required, suck up wsp before ;
          (?= ; )              # ;
      
       |                     # or,
      
          (?<= ; )             # ;
          \s+                  # Required, suck up wsp after ;
      
       |                     # or,
      
          (?<! \s )            # No wsp before ;
          (?= ; )              # ;
      
       |                     # or,
      
          (?<= ; )             # ;
          (?! \s )             # No wsp after ;
      
       |                     # or,
      
          (?<! ^ )             # No split of wsp at BOS   
          (?<! \s )
          \s+                  # Required wsp
      

      【讨论】:

      • 这几乎可以工作,但它包括初始空格作为附加拆分(“a” -> ["", "a"] 而不是 ["a"])。
      • 如果你想允许这些额外的空间,只需要一个断言。[
      • 我不太确定你在说什么。当我在 Java 中使用 String.split() 将您的正则表达式应用于“a”时,它会在拆分列表中提供两个元素(空字符串和“a”)。我希望并期望它只返回一个(“a”)。
      • 我会为您进行编辑,请稍等。拆分不会让您修剪内联,但您可以将“a”匹配为一个元素,然后在元素 0 上进行修剪。您可以这样做吗?
      • 其实我想我误解了Java是如何分割字符串的;不包括尾随的空字符串,但不包括前导字符串。
      【解决方案6】:

      借用@CasimiretHippolyte \G 你可能想要拆分的技巧

      \\s+|(?!\\G)()
      

      注意:没有指定分隔符。

      更新

      基于避免在第一个空格上拆分:

      (?m)(?<!^|\\s)(\\s+|)(?!$)
      

      【讨论】:

      • 为什么最后是空的捕获组“()”?它似乎什么也没做,没有它似乎也能正常工作。
      • 是的捕获组仅用于详细说明。我还更新了我的答案以适应您的新要求。请检查。 @M.贾斯汀
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-23
      • 1970-01-01
      • 2013-08-08
      • 2016-11-26
      • 1970-01-01
      • 2022-11-03
      相关资源
      最近更新 更多