在安卓系统中,BreakIterator是如何工作的?

8
我正在Android上制作自己的文本处理器(用于蒙古语的自定义垂直脚本TextView)。我原以为需要自己找到所有换行位置,以便实现换行,但后来我发现了BreakIterator。它似乎可以在各种语言中找到字符、单词、行和句子之间的所有可能断点。
我正在尝试学习如何使用它。文档比平均水平更有帮助,但仅仅从阅读中理解还是有些困难。我还找到了一些教程(请参见这里这里这里),但它们缺少我所寻找的带有输出的完整解释。
我正在添加这个问答式的答案,以帮助自己学习如何使用BreakIterator
我将这个标签添加到Android和Java中,因为它们之间显然有一些区别。此外,Android现在支持ICU BreakIterator,未来的答案可能会涉及到这一点。
1个回答

20

BreakIterator 可用于查找字符、单词、行和句子之间的可能断点。这对于通过可见字符移动光标,双击选择单词,三击选择句子和换行等操作非常有用。

样板代码

以下代码在下面的示例中使用。只需调整第一部分以更改 BreakIterator 的文本和类型即可。

// change these two lines for the following examples
String text = "This is some text.";
BreakIterator boundary = BreakIterator.getCharacterInstance();

// boiler plate code
boundary.setText(text);
int start = boundary.first();
for (int end = boundary.next(); end != BreakIterator.DONE; end = boundary.next()) {
    System.out.println(start + " " + text.substring(start, end));
    start = end;
}

如果您只想测试一下,可以直接将它粘贴到 Android 中的 Activity 的 onCreate 中。我使用了 System.out.println 而不是 Log,这样它也可在仅 Java 环境中进行测试。

我使用的是 java.text.BreakIterator,而不是 ICU 版本,ICU 版本只能从 API 24 开始使用。有关更多信息,请参见底部链接。

Characters

更改样板代码以包括以下内容

String text = "Hi 中文éé\uD83D\uDE00\uD83C\uDDEE\uD83C\uDDF3.";
BreakIterator breakIterator = BreakIterator.getCharacterInstance();

输出

0 H
1 i
2  
3 中
4 文
5 é
6 é
8 
10 
14 .

最有趣的部分位于索引6810。您的浏览器可能会正确显示这些字符,也可能不会,但用户会将它们解释为单个字符,即使它们由多个UTF-16值组成。

词汇

更改模板代码以包括以下内容:

String text = "I like to eat apples. 我喜欢吃苹果。";
BreakIterator boundary = BreakIterator.getWordInstance();

输出

0 I
1  
2 like
6  
7 to
9  
10 eat
13  
14 apples
20 .
21  
22 我
23 喜欢
25 吃
26 苹果
28 。

这里有几个有趣的事情需要注意。首先,在空格的两侧都检测到了单词中断。其次,即使有不同的语言,也可以识别出多个字符的中文单词。即使我将区域设置为 Locale.US,在我的测试中仍然如此。

你可以像单词示例一样保持代码不变:

String text = "I like to eat apples. 我喜欢吃苹果。";
BreakIterator boundary = BreakIterator.getLineInstance();

输出

0 I 
2 like 
7 to 
10 eat 
14 apples. 
22 我
23 喜
24 欢
25 吃
26 苹
27 果。

请注意,断点位置不是整行文本。它们只是方便的文本换行位置。

输出与“Words”示例类似。但现在包括了单词前面的空格和标点符号。这是有道理的,因为你不希望新的一行以空格或标点符号开头。还要注意,每个中文字符都有换行符。这是符合事实的,因为在中文中跨行拆分多字符单词是可以接受的。

句子

更改样板代码以包含以下内容:

String text = "I like to eat apples. My email is me@example.com.\n" +
        "This is a new paragraph. 我喜欢吃苹果。我不爱吃臭豆腐。";
BreakIterator boundary = BreakIterator.getSentenceInstance();

输出

0 I like to eat apples. 
22 My email is me@example.com.
50 This is a new paragraph. 
75 我喜欢吃苹果。
82 我不爱吃臭豆腐。

正确的句子分割在多种语言中都得到了认可。此外,在电子邮件域中没有出现错误的正点。

注释

您可以在创建BreakIterator时设置Locale,但如果没有设置,则使用默认的locale

进一步阅读


将中文文本分解成单词对我来说不起作用。你能看一下这个链接吗:https://dev59.com/96Lia4cB1Zd3GeqPkYbd? - srgsanky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接