【问题标题】:Split regex with multi char delimiters使用多字符分隔符拆分正则表达式
【发布时间】:2018-12-01 11:56:48
【问题描述】:

我正在努力寻找在 Java 中使用带有多个字符的分隔符来拆分字符串的正确方法(例如 '.[1a]' 或 '.(2b)')

这是一个测试用例:

String str1 = "This is test 1  .  This is test 2  [2 b]. This is test 3 (3). This is test 4.[4a] This is a test 5 . This is test 6 . (6,six)";

Pattern regex = Pattern.compile("\\.\\s{0,}\\[.*\\]\\s{0,}|\\.\\s{0,}\\(.*\\)\\s{0,}|\\.\\s{0}");

System.out.println(Arrays.toString(regex.split(text)));

我的目标输出如下(每个子字符串开头或结尾的空格都可以,重要的是保留分隔符):

[这是测试 1。 , 这是测试 2 [2 b]。 , 这是测试 3 (3)。 , 这是测试 4.[4a] ,这是测试 5 。 , 这是测试6。 (6,6)]

但是,这是我得到的输出:

[这是测试 1,这是测试 2 [2 b],这是测试 3 (3),这是 测试4,这是测试5,这是测试6]

还尝试删除“\\s”,这是Pattern.compile("\\s+\\[.?\\]\\s+\\.|\\s+\\(.?\\)\\s+\\.|\\.\\s+") 等空格的不同表示法,并尝试使用Pattern.compile("(?<=[.[*]\\s+])|(?=[.(*)]\\s+)|\\.") 之类的前瞻,但都没有帮助:|

【问题讨论】:

    标签: java regex regex-lookarounds


    【解决方案1】:

    这可能有点棘手。关注通缉组在下一个组开始时结束的共同特征 - 有一个字母\w,所以用它来检测一个新组。

    利用这一优势将其替换为 self 和之前的 \n,因此 \n$1 和每个组将出现在一个新行上,这很容易提取。想要的正则表达式(见Regex101)是:

     (?<!\w )(\w)(?=\w{2,})
    
    • 注意正则表达式第一个字符处的(空格)!

    这将产生如下输出:

    This is test 1  . 
    This is test 2  [2 b].
    This is test 3 (3).
    This is test 4.[4a]
    This is a test 5 .
    This is test 6 . (6,six)
    

    在 Java 中,代码将使用 replaceAll 和 split 方法(感谢 @jmng 的改进):

    String str1 = "This is test 1  .  This is test 2  [2 b]. This is test 3 (3). This is test 4.[4a] This is a test 5 . This is test 6 . (6,six)";
    
    Pattern reg1 = Pattern.compile(" (?<!\\w )(\\w)(?=\\w{2,})");              // Preparation
    Pattern regNewline = Pattern.compile("\n");                                // Split
    String[] array = regNewline.split(reg1.matcher(str1).replaceAll("\n$1"));  // Apply
    
    
    Arrays.stream(array).forEach(System.out::println);                         // Test it
    

    【讨论】:

    • 这行得通,实际上可以处理平滑变化,如多个部分分隔符(例如 [][])或添加或删除空格等细微变化。虽然我必须承认,我需要一段时间才能理解它! :P
    • 利用已编译的模式:Pattern reg1 = Pattern.compile(" (?&lt;!\\w )(\\w)(?=\\w{2,})"); Pattern regNewline = Pattern.compile("\n"); String str1 ="text to regex [whatever]"; regNewline.split(reg1.matcher(str1).replaceAll("\n$1"));
    • 你也教我,我之前没用过Pattern::split。经您许可,我会将其包含在答案中。
    【解决方案2】:

    如果每个子字符串的开头或结尾的空格是可以接受的并且使用拆分,则一种可能性是使用替代方案,并积极地向后检查您的不同要求。

    在 Java 中,您必须确定后视的最小和最大可能长度,例如,您可能会为示例数据取 10。

    (?&lt;=\[[^]]{1,10}]\.|\.\[[^]]{1,10}]|\([^)]{1,10}\)\.| \. (?!\([^)]+\)))

    在 Java 中:

    (?&lt;=\\[[^]]{1,10}]\\.|\\.\\[[^]]{1,10}]|\\([^)]{1,10}\\)\\.| \\. (?!\\([^)]+\\)))

    说明

    • (?&lt;= 积极的后视检查左边是什么
      • \[[^]]{1,10}]\. 使用否定字符类来匹配方括号和不重复右括号 1 - 10 次后跟一个点的量词
      • |或者
      • \.\[[^]]{1,10}] 匹配点并使用否定字符类在方括号和不重复右括号的量词之间匹配 1 - 10 次
      • |或者
      • \([^)]{1,10}\)\. 使用否定字符类来匹配括号和量词,而不是重复右括号 1 - 10 次
      • |或者
      • \. (?!\([^)]+\)) 一个空格、点和一个空格,如果后面的内容不是括号之间的任何内容
    • ) 近距离正面观察

    Java demo

    【讨论】:

    • 谢谢,我检查了你的演示,但我不确定输出是否匹配。数组的最后一个元素应该是“This is test 6 . (6,six)”,似乎有两个元素没有被拆分(“This is test 4.[4a] This is a test 5 . ");还是我解释错了?
    • @jmng 你是对的,我已经更新了我的答案并添加到在点之前或之后的方括号上拆分。当后面没有括号时,也只在空格点空间上分割。
    • 新版本确实适用于给定的示例,但似乎 Nikolas 的建议更可靠,例如它可以处理多个部分分隔符(例如 [][])等平滑变化或添加或删除空格等细微变化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 2014-11-22
    • 2011-02-24
    • 1970-01-01
    相关资源
    最近更新 更多