Java字符串标记化:在模式上拆分并保留模式

时间:2017-08-29 08:58:46

标签: java regex string scala tokenize

我的问题是Python上this查询的Scala(Java)变体。

特别是,我有一个字符串val myStr = "Shall we meet at, let's say, 8:45 AM?"。我想将它标记为保留分隔符(除了空白之外的所有分隔符)。如果我的分隔符只是字符,例如.:?等我可以这样做:

val strArr = myStr.split("((\\s+)|(?=[,.;:?])|(?<=\\b[,.;:?]))")

产生

[Shall, we, meet, at, ,, let's, say, ,, 8, :, 45, AM, ?]

但是,我希望将时间签名\\d+:\\d+作为分隔符,并且仍希望保留它。所以,我想要的是

[Shall, we, meet, at, ,, let's, say, ,, 8:45, AM, ?]

注意:

  1. 在split语句的表达式中添加析取(?=(\\d+:\\d+))没有帮助
  2. 在签名之外,:本身就是一个分隔符
  3. 我怎么能做到这一点?

2 个答案:

答案 0 :(得分:1)

我建议您匹配所有令牌,而不是拆分字符串,因为这样您可以更好地控制所获得的内容:

 \b\d{1,2}:\d{2}\b|[,.;:?]+|(?:(?!\b\d{1,2}:\d{2}\b)[^\s,.;:?])+

请参阅regex demo

我们开始匹配最具体的模式,最后一个是最通用的模式。

<强>详情

  • \b\d{1,2}:\d{2}\b - 1到2位数,:,包含字边界的2位数字
  • | - 或
  • [,.;:?]+ - 1个或多个,.;:?字符
  • | - 或
  • (?:(?!\b\d{1,2}:\d{2}\b)[^\s,.;:?])+ - 匹配任何不是我们的分隔符char或空格([^\s,.;:?])的char,它不是时间字符串的起点。

考虑this snippet

val str = "Shall we meet at, let's say, 8:45 AM?"
var rx = """\b\d{1,2}:\d{2}\b|[,.;:?]+|(?:(?!\b\d{1,2}:\d{2}\b)[^\s,.;:?])+""".r
rx findAllIn str foreach println

输出:

Shall
we
meet
at
,
let's
say
,
8:45
AM
?

答案 1 :(得分:-1)

public class StringPatternTokenizer {
    Pattern pattern;

    public StringPatternTokenizer(String regex) {
        this.pattern = Pattern.compile(regex);
    }

    public void getTokens(String str, NextToken nextToken) {
        Matcher matcher = pattern.matcher(str);

        int index = 0;
        Result result = null;
        while (matcher.find()) {
            if (matcher.start() > index) {
                result = nextToken.visit(null, str.substring(index, matcher.start()));
            }
            if (result != Result.STOP) {
                index = matcher.end();
                result = nextToken.visit(matcher, null);
            }

            if (result == Result.STOP) {
                return;
            }
        }

        if (index < str.length()) {
            nextToken.visit(null, str.substring(index));
        }
    }

    enum Result {
        CONTINUE,
        STOP,
    }

    public interface NextToken {
        Result visit(Matcher matcher, String str);
    }

    /***** test cases FOR IT *****/
    public void testCase() {
        new StringPatternTokenizer(regex).getTokens(value, (matcher, str) -> {
            if (matcher != null) {
                System.out.println("part: " + matchStr);
            } else {
                System.out.println("part(stuff): " + str);
            }

            return StringPatternTokenizer.Result.CONTINUE;
        });
    }
}