【问题标题】:Splitting whole text to words using one regex使用一个正则表达式将整个文本拆分为单词
【发布时间】:2016-04-29 14:53:49
【问题描述】:

我正在寻找问题的解决方案。我需要创建一种方法来创建单词列表和只是单词,对于任何给定的文本,包括非英文字母和特殊字符。我进行了很多搜索,并且正在阅读文档here,但这对我来说并不完美。最好的之一是这个:

String line = "    W metal, w liczbę, w trupie ciało, -"
String[] words = line.split("\\P{javaLetter}+");
    for (int i = 0; i < words.length; i++) {
        if (!words[i].equals("")) {  // I don't want to check everytime
            anotherList.add(word[i].toLowerCase())
        }
    }
}

但结果是:

["", "W", "metal", "w", "liczbę", "w", "trupie", "ciało"]

字符串开头的这个空格破坏了我的正则表达式。 哪个是使用拉丁字母在任何语言中生成单词的正确正则表达式(不关心英文单词中的撇号)?

【问题讨论】:

  • 你试过 line.Split(" ") 吗?拆分空格以获取句子中的单词是有意义的。正则表达式很棒,但也很挑剔。
  • 您打印的是words 还是anotherList
  • @tobias_k 显然是字,因为 anotherList 不会有他的结果的第一个索引中存在的空字符串。
  • @RichardBarker 我问的原因是什么,但问题并不清楚。所以我想实际的问题是:使用什么正则表达式使wordsanotherList 立即相同?
  • 真的需要拆分吗?您可以使用模式并遍历匹配项吗?

标签: java regex string split


【解决方案1】:

你可以使用相反的方法——匹配:

List<String> words = new ArrayList<>();
String line = "    W metal, w liczbę, w trupie ciało, -";
Matcher m = Pattern.compile("\\p{L}+").matcher(line);
while (m.find()) {
    words.add(m.group());
}
System.out.println(words); // => [W, metal, w, liczbę, w, trupie, ciało]

请参阅IDEONE demo\\p{L}+ 将匹配 1+ 任何 Unicode 字母。

有一种方法可以使用拆分的方法,但是我们需要先对输入的字符串进行预处理:

String line = "    W metal, w liczbę, w trupie ciało, -";
String[] words = line.replaceFirst("^\\P{L}+", "").split("\\P{L}+");
System.out.println(Arrays.toString(words));

another IDEONE demo

.replaceFirst("^\\P{L}+", "") 将删除字符串开头的所有非字母符号,因此,拆分数组中不会留下空元素。

【讨论】:

  • 我想这更好的方法。不过,遗憾的是 Java 没有更简单的方法来获取所有匹配项。
  • 最佳解决方案。谢谢你。我不必使用拆分,但我认为这是最简单的方法。
【解决方案2】:

假设您希望words 的结果与anotherList 相同,但没有在循环中对结果进行后处理。那么进行一些预处理怎么样?

String line = "    W  metal,  w  liczbę,   w  trupie ciało, -";
String[] words = line.trim().toLowerCase().split("\\P{javaLetter}+");
System.out.println(Arrays.toString(words));

结果:[w, metal, w, liczbę, w, trupie, ciało]

【讨论】:

  • 如果开头有非字母/非空格? :)
  • @WiktorStribiżew 好吧,我想在这种情况下,结果中仍然会有一些 ''... :-/
【解决方案3】:

首先是我添加的变体中的单引号。然后是所有字母,以及与字母组合的零宽度重音符号。

String[] rawWords = line.trim().split("(?U)[^\\p{L}\\p{M}'\u0060\u00b4\u2017]");

在 Pattern 的 javadoc 中查找正则表达式。

如果该行不以单词开头,这不会阻止前面的空单词。也可以更换,但支票就足够了。

另一个问题是,每个单引号都被认为是单词的一部分。 这可以通过删除单词引号的所有前导和尾随序列来完成。

我不会尝试制作一个单一的正则表达式,尽管这对于引用问题肯定是可能的。

一种简化是使用 Unicode 文本规范化。 "ŝ" 可以是一个字符\u0150 或两个字符c 加上一个零宽度^。这可以通过java.text.Normalizer 类来完成。那么\\p{M} 如果您使用组合形式,则不再需要。 此外,所有这些单引号都可以替换为撇号 '

(对于自然语言处理,JNLP 可能会感兴趣。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-30
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多