【问题标题】:Split on regex and capture matched delimiter expression in Java?在 Java 中拆分正则表达式并捕获匹配的分隔符表达式?
【发布时间】:2017-01-25 22:24:16
【问题描述】:

我正在尝试解析一个文本文件,其中包含一系列以数字开头的“记录”(后跟 NBSP 和 1-2 个空格),包含数百个字母和数字字符,跨越换行符,但是不要以任何可预测的事情结束。识别记录结束的唯一方法是点击起始标记的下一个实例,可以通过以下正则表达式匹配:

\\d{1,4}\\u00A0\\s+ 

内容是手动输入的,有不可预知的换行符,所以我把它们删掉了。这给我留下了一个字符串。

1  blah blah blah  2  blah blah blah ... 875  blah blah blah 

由于我知道记录已结束的唯一方法是点击下一个记录 ID,因此我尝试仅拆分上面的正则表达式。这会将文件正确拆分为记录,但它省略了我需要捕获的记录 ID。我检查了 Java 文档,但没有任何关于捕获被分割的动态值的内容。我尝试将记录号设为捕获组,但该数据未保留在结果数组中。

这个问题(Java String Regex split and capture splitted portion)看起来很相似,但是提问者知道每个文本片段的结束位置;而我只知道每个开始的地方。

那么是否有另一种拆分方式,但通过拆分正则表达式保留文本匹配?

谢谢

【问题讨论】:

    标签: java regex string split


    【解决方案1】:

    不要使用split(),而是编写自己的正则表达式循环,例如

    String input = "...your input...";
    Matcher m = Pattern.compile("\\d{1,4}\\u00A0\\s+").matcher(input);
    int prev = 0;
    while (m.find()) {
        String prevText = input.substring(prev, m.start());
        prev = m.end();
        String delimiter = m.group();
        // ... code here ...
    }
    String tailText = input.substring(prev); // text after last delimiter
    // ... code here ...
    

    【讨论】:

    • 变体:Pattern.compile("(.*?)(\\d{1,4}\\u00A0\\s+)", Pattern.DOTALL); while (m.find()) { String prevText = m.group(1); String delimiter = m.group(2); ... }。或者,如果您关心末尾的未终止位:String delimiter; Pattern.compile("(.*?)(\\d{1,4}\\u00A0\\s+|$)", Pattern.DOTALL); while (! "".equals(delimiter)) { m.find(); String prevText = m.group(1); delimiter = m.group(2); ... }
    • @DavidKnipe 第一部分没用,因为你肯定关心尾部文本,因为分隔符是前缀,而不是终止符。 --- 对于第二部分,您刚刚导致了 IllegalStateException,因为这就是在 find() 返回 false 之后调用 group() 时发生的情况。在 javadoc 中有这么说。 --- 嗯,我的意思是,这就是在以某种方式修复 delimiter 未初始化的编译错误后会发生的情况。
    • find() 不应该返回 false,因为我在正则表达式中添加了 |$,所以它应该在没有分隔符的情况下仍然匹配。并将String delimiter; 更改为String delimiter = null;
    【解决方案2】:

    如果您只想检查您的文本之后是否存在其他文本,但不包括匹配中的其他文本(例如检查 foo 之后是否为 bar 但不包括 bar 匹配),那么您就是寻找look-around mechanism,或者更准确地说,积极向前看(?=...)

    让我们从split("(?=\\d{1,4}\\u00A0\\s+)") 开始。这将在后面有 NBSP 和一些空格的任何 1-4 位数字系列之前拆分。问题在于对于像

    这样的文本
    1234[nbsp]___ 
    

    这描述了地点(标有|

    |1234[nbsp]___ 
    1|234[nbsp]___ 
    12|34[nbsp]___ 
    123|4[nbsp]___ 
    

    但我们不希望允许在数字之间进行拆分。我们必须添加条件来防止这种分裂。因此,如果我们可以说“在分割位置之前不能有数字”,那就太好了。为此,我们可以在(?<!...) 后面使用否定外观,在我们的例子中看起来像(?<!\\d)

    所以最终解决方案看起来像

    split("(?<!\\d)(?=\\d{1,4}\\u00A0\\s+)")
    

    【讨论】:

    • 啊。非常好。对于后代:这种拆分方法允许我在每个拆分行中保留与正则表达式匹配的动态分隔符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多