使用拆分方法创建令牌生成器

时间:2018-10-26 20:36:24

标签: java design-patterns split token tokenize

我正在尝试创建一个简单的标记生成器,该标记可在空格上分割,小写标记,删除所有非字母字符并仅保留3个或更多字符的术语。我编写了这段代码,所有小写字母,非字母字符都可以使用,并且只能保留3个或更多字符。但是我想使用split方法,但是我不知道怎么做。请提出一些建议。

public class main {

    public static final String EXAMPLE_TEST = "This Mariana John bar Barr "
        + "12364 FFFFF aaaa a s d f g.";

    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("(\\s[a-z]{3,20})");
        Matcher matcher = pattern.matcher(EXAMPLE_TEST);

        while (matcher.find()) {
            System.out.print("Start index: " + matcher.start());
            System.out.print(" End index: " + matcher.end() + " ");
            System.out.println(matcher.group());
        }
    }
}

2 个答案:

答案 0 :(得分:1)

如果您不必跟踪索引:

List<String> processed = Arrays.stream(EXAMPLE_TEST.split(" ")).map(String::toLowerCase)
            .map(s -> s.replaceAll("[^a-z]", "")).filter(s -> s.length() >= 3).collect(Collectors.toList());
for (String s : processed) {
    System.out.println(s);
}

但是您的示例输出也显示了索引。然后,您必须将其存储在其他容器中(例如地图):

Map<Integer, String> processed = Arrays.stream(EXAMPLE_TEST.split(" ")).collect(Collectors.toMap(s -> EXAMPLE_TEST.indexOf(s), s -> s.toLowerCase().replaceAll("[^a-z]", "")));
Map<Integer, String> filtered = processed.entrySet().stream().filter(entry -> entry.getValue().length() >= 3).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
for (Map.Entry<Integer, String> entry : filtered.entrySet()) {
    System.out.println("Start index: " + entry.getKey() + " " + entry.getValue());
}

答案 1 :(得分:0)

由于您的要求在任何地方都不会说“最大20”,因此可以将[a-z]{3,20}更改为[a-z]{3,},以无限制的长度。

正则表达式不能小写令牌,因此您需要分别调用toLowerCase()。您的正则表达式只有在调用正则表达式之前 才能正常运行。如果打算在调用正则表达式后在每个令牌上调用toLowerCase(),则需要将[a-z]更改为[a-zA-Z]。最简单的就是这样做。

以上表示您的代码应进行如下修改:

Pattern pattern = Pattern.compile("[a-z]{3,}");
Matcher matcher = pattern.matcher(EXAMPLE_TEST.toLowerCase());

输出

Start index: 0 End index: 4 this
Start index: 5 End index: 12 mariana
Start index: 13 End index: 17 john
Start index: 18 End index: 21 bar
Start index: 22 End index: 26 barr
Start index: 33 End index: 38 fffff
Start index: 39 End index: 43 aaaa

要使用split执行相同的操作,您需要分割由非字母字符或最多2个连续字母字符组成的任何字符序列。

String[] split = EXAMPLE_TEST.toLowerCase().split("(?:[^a-z]+|(?<![a-z])[a-z]{1,2}(?![a-z]))+");
System.out.println(Arrays.toString(split));

输出

[this, mariana, john, bar, barr, fffff, aaaa]

说明:

(?:              Start non-capturing repeating group:
   [^a-z]+           Match one or more nonalphabetic characters
 |                 Or
   (?<![a-z])        Not preceded by an alphabetic character
   [a-z]{1,2}        Match 1-2 alphabetic characters
   (?![a-z])         Not followed by an alphabetic character
)+               Match one or more of the above

注意:可以删除+之后的[^a-z],因为末尾的+仍会重复,但是正则表达式的效果应更好+在这里。

原始代码和拆分代码之间的区别在于,如果输入以非字母字符开头,则split将返回一个空字符串作为第一个结果。