BreakIterator 在 Android 中如何工作?

How does BreakIterator work in Android?

我正在 Android(蒙古语的自定义垂直脚本 TextView)中制作自己的文本处理器。我以为我必须自己找到所有的换行位置才能实现换行,但后来我发现BreakIterator。这似乎找到了各种语言中字符、单词、行和句子之间所有可能的断点。

我正在努力学习如何使用它。 documentation was more helpful than average, but it was still difficult to understand from just reading. I also found a few tutorials (see here, here, and here) 但他们缺乏我正在寻找的输出的完整解释。

我正在添加此问答式答案以帮助自己学习如何使用 BreakIterator

除了 Java 之外,我还把它设为 Android 标签,因为还有 apparently some difference between them. Also, Android now supports the ICU BreakIterator,以后的答案可能会处理这个问题。

BreakIterator 可用于查找字符、单词、行和句子之间可能的中断。这对于将光标移动到可见字符、双击 select 个单词、三次单击 select 个句子和换行等操作很有用。

样板代码

以下示例中使用了以下代码。只需调整第一部分即可更改 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,后者只能从 API 24 获得。有关详细信息,请参阅底部的链接。

字符数

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

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 。

这里有一些有趣的事情需要注意。首先,在 space 的两边检测到断字。其次,即使有不同的语言,multi-character 中文单词仍然被识别。即使我将语言环境设置为 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 示例。但是,现在白色 space 和标点符号包含在它前面的单词中。这是有道理的,因为您不希望新行以白色 space 或标点符号开头。另请注意,汉字会为每个字符换行。这与中文中跨行打断multi-character字是可以的是一致的

句子

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

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 我不爱吃臭豆腐。

可以在多种语言中识别正确的断句。此外,电子邮件域中的点没有误报。

注释

您可以设置 Locale when you create a BreakIterator, but if you don't it just uses the default locale.

进一步阅读