Java 中文官方教程 2022 版(三十)(2)

简介: Java 中文官方教程 2022 版(三十)

Java 中文官方教程 2022 版(三十)(1)https://developer.aliyun.com/article/1487956

示例用法

原文:docs.oracle.com/javase/tutorial/i18n/text/usage.html

本页面包含一些代码片段,展示了几种常见场景。

从代码点创建 String

String newString(int codePoint) {
    return new String(Character.toChars(codePoint));
}

从代码点创建 String - 为 BMP 字符进行优化

Character.toChars 方法创建一个临时数组,仅使用一次然后丢弃。如果这对性能产生负面影响,你可以使用以下针对 BMP 字符(由单个 char 值表示的字符)进行优化的方法。在这种方法中,toChars 仅用于补充字符。

String newString(int codePoint) {
    if (Character.charCount(codePoint) == 1) {
        return String.valueOf(codePoint);
    } else {
        return new String(Character.toChars(codePoint));
    }
}

批量创建 String 对象

要创建大量字符串,前面代码片段的批量版本重用了 toChars 方法使用的数组。该方法为每个代码点创建一个单独的 String 实例,并针对 BMP 字符进行了优化。

String[] newStrings(int[] codePoints) {
    String[] result = new String[codePoints.length];
    char[] codeUnits = new char[2];
    for (int i = 0; i < codePoints.length; i++) {
        int count = Character.toChars(codePoints[i], codeUnits, 0);
        result[i] = new String(codeUnits, 0, count);
    }
    return result;
}

生成消息

格式化 API 支持补充字符。以下示例是生成消息的简单方法。

// recommended
System.out.printf("Character %c is invalid.%n", codePoint);

以下方法简单且避免了连接,这使得文本更难本地化,因为并非所有语言都按照英语的顺序将数字值插入字符串中。

// not recommended
System.out.println("Character " + String.valueOf(char) + " is invalid.");

设计考虑事项

原文:docs.oracle.com/javase/tutorial/i18n/text/design.html

要编写能够无缝运行于任何语言和任何脚本的代码,有几点需要牢记。

考虑事项 原因
避免使用char数据类型的方法。 避免使用char原始数据类型或使用char数据类型的方法,因为使用该数据类型的代码对补充字符不起作用。对于需要char类型参数的方法,尽可能使用相应的int方法。例如,使用Character.isDigit(int)方法而不是Character.isDigit(char)方法。
使用isValidCodePoint方法验证代码点值。 代码点被定义为int数据类型,允许值超出从 0x0000 到 0x10FFFF 的有效代码点值范围。出于性能原因,接受代码点值作为参数的方法不会检查参数的有效性,但您可以使用isValidCodePoint方法检查该值。
使用codePointCount方法计算字符数。 String.length()方法返回字符串中代码单元或 16 位char值的数量。如果字符串包含补充字符,则计数可能会误导,因为它不会反映真实的代码点数量。要准确计算字符数(包括补充字符),请使用codePointCount方法。
使用String.toUpperCase(int codePoint)String.toLowerCase(int codePoint)方法而不是Character.toUpperCase(int codePoint)Character.toLowerCase(int codePoint)方法。 虽然Character.toUpperCase(int)Character.toLowerCase(int)方法可以处理代码点值,但有些字符无法进行一对一转换。例如,德语小写字符ß在转换为大写时变为两个字符 SS。同样,希腊语小写 Sigma 字符在字符串中的位置不同而有所不同。Character.toUpperCase(int)Character.toLowerCase(int)方法无法处理这些情况;然而,String.toUpperCaseString.toLowerCase方法可以正确处理这些情况。
删除字符时要小心。 在调用StringBuilder.deleteCharAt(int index)StringBuffer.deleteCharAt(int index)方法时,索引指向补充字符时,只会删除该字符的前半部分(第一个char值)。首先,调用Character.charCount方法对字符进行检查,以确定必须删除一个或两个char值。
在对序列中的字符进行反转时要小心。当在包含补充字符的文本上调用StringBuffer.reverse()StringBuilder.reverse()方法时,高低代理对会被反转,导致不正确甚至可能无效的代理对。

更多信息

原文:docs.oracle.com/javase/tutorial/i18n/text/info.html

有关补充字符的更多信息,请参考以下资源。

检测文本边界

原文:docs.oracle.com/javase/tutorial/i18n/text/boundaryintro.html

操纵文本的应用程序需要定位文本内的边界。例如,考虑一些文字处理器的常见功能:突出显示一个字符,剪切一个单词,将光标移动到下一个句子,以及在行尾换行一个单词。为了执行这些功能,文字处理器必须能够检测文本中的逻辑边界。幸运的是,您不必编写自己的例程来执行边界分析。相反,您可以利用BreakIterator类提供的方法。

关于 BreakIterator 类

本节讨论了BreakIterator类的实例化方法和虚拟光标。

字符边界

在本节中,您将了解用户字符和 Unicode 字符之间的区别,以及如何使用BreakIterator定位用户字符。

词边界

如果您的应用程序需要在文本中选择或定位单词,使用BreakIterator会很有帮助。

句子边界

确定句子边界可能会有问题,因为许多书面语言中句子终止符的使用是模棱两可的。本节将讨论您可能遇到的一些问题,以及BreakIterator如何处理这些问题。

行边界

本节描述了如何使用BreakIterator在文本字符串中定位潜在的换行符。

关于 BreakIterator 类

原文:docs.oracle.com/javase/tutorial/i18n/text/about.html

BreakIterator类是区域敏感的,因为文本边界随语言而变化。例如,换行的语法规则并非所有语言都相同。要确定BreakIterator类支持哪些区域设置,请调用getAvailableLocales方法,如下所示:

Locale[] locales = BreakIterator.getAvailableLocales();

您可以使用BreakIterator类分析四种边界类型:字符、单词、句子和潜在的换行符。在实例化BreakIterator时,调用适当的工厂方法:

  • getCharacterInstance
  • getWordInstance
  • getSentenceInstance
  • getLineInstance

每个BreakIterator实例只能检测一种类型的边界。例如,如果您想定位字符和单词边界,您需要创建两个单独的实例。

BreakIterator具有一个想象的光标,指向文本字符串中的当前边界。您可以使用previousnext方法在文本中移动此光标。例如,如果您使用getWordInstance创建了一个BreakIterator,每次调用next方法时,光标都会移动到文本中的下一个单词边界。光标移动方法返回一个整数,指示边界的位置。此位置是文本字符串中将跟随边界的字符的索引。与字符串索引一样,边界是从零开始的。第一个边界在 0 处,最后一个边界是字符串的长度。以下图显示了nextprevious方法在文本行中检测到的单词边界:


*此图已经缩小以适应页面。

点击图像以查看其自然大小。*

您应该仅将BreakIterator类与自然语言文本一起使用。要对编程语言进行标记化,请使用StreamTokenizer类。

接下来的部分为每种边界分析类型提供示例。编码示例来自名为BreakIteratorDemo.java的源代码文件。

字符边界

原文:docs.oracle.com/javase/tutorial/i18n/text/char.html

如果您的应用程序允许最终用户突出显示单个字符或逐个字符地移动光标穿过文本,则需要定位字符边界。要创建一个定位字符边界的BreakIterator,您可以调用getCharacterInstance方法,如下所示:

BreakIterator characterIterator =
    BreakIterator.getCharacterInstance(currentLocale);

这种类型的BreakIterator检测用户字符之间的边界,而不仅仅是 Unicode 字符。

用户字符可能由多个 Unicode 字符组成。例如,用户字符ü可以由组合 Unicode 字符\u0075(u)和\u00a8(¨)组成。然而,这并不是最好的例子,因为字符ü也可以用单个 Unicode 字符\u00fc 表示。我们将借助阿拉伯语言来举一个更现实的例子。

在阿拉伯语中,房子的单词是:


这个词包含三个用户字符,但它由以下六个 Unicode 字符组成:

String house = "\u0628" + "\u064e" + "\u064a" + "\u0652" + "\u067a" + "\u064f";

字符串house中位置 1、3 和 5 的 Unicode 字符是变音符号。阿拉伯语需要变音符号,因为它们可以改变单词的含义。示例中的变音符号是非间隔字符,因为它们出现在基本字符的上方。在阿拉伯语文字处理器中,您不能在屏幕上每个 Unicode 字符移动一次光标。相反,您必须为每个用户字符移动一次光标,这可能由多个 Unicode 字符组成。因此,您必须使用BreakIterator来扫描字符串中的用户字符。

示例程序BreakIteratorDemo创建一个BreakIterator来扫描阿拉伯字符。程序将这个BreakIterator与先前创建的String对象一起传递给名为listPositions的方法:

BreakIterator arCharIterator = BreakIterator.getCharacterInstance(
                                   new Locale ("ar","SA"));
listPositions (house, arCharIterator);

listPositions方法使用BreakIterator来定位字符串中的字符边界。请注意,BreakIteratorDemo使用setText方法将特定字符串分配给BreakIterator。程序使用first方法检索第一个字符边界,然后调用next方法,直到返回常量BreakIterator.DONE。此例程的代码如下:

static void listPositions(String target, BreakIterator iterator) {
    iterator.setText(target);
    int boundary = iterator.first();
    while (boundary != BreakIterator.DONE) {
        System.out.println (boundary);
        boundary = iterator.next();
    }
}

listPositions方法打印出字符串house中用户字符的以下边界位置。请注意,变音符号的位置(1、3、5)没有列出:

0
2
4
6

单词边界

原文:docs.oracle.com/javase/tutorial/i18n/text/word.html

您调用getWordIterator方法来实例化一个检测单词边界的BreakIterator

BreakIterator wordIterator =
    BreakIterator.getWordInstance(currentLocale);

当您的应用程序需要对单词执行操作时,您会想要创建这样一个BreakIterator。这些操作可能是常见的单词处理功能,如选择、剪切、粘贴和复制。或者,您的应用程序可能会搜索单词,并且必须能够区分整个单词和简单字符串。

BreakIterator分析单词边界时,它区分单词和不属于单词的字符。这些字符包括空格、制表符、标点符号和大多数符号,在两侧都有单词边界。

接下来的示例来自程序BreakIteratorDemo,标记了一些文本中的单词边界。该程序创建了BreakIterator,然后调用markBoundaries方法:

Locale currentLocale = new Locale ("en","US");
BreakIterator wordIterator =
    BreakIterator.getWordInstance(currentLocale);
String someText = "She stopped. " +
    "She said, \"Hello there,\" and then went " +
    "on.";
markBoundaries(someText, wordIterator);

markBoundaries方法在BreakIteratorDemo.java中定义。该方法通过在目标字符串下方打印插入符号(^)来标记边界。在接下来的代码中,请注意while循环,其中markBoundaries通过调用next方法扫描字符串:

static void markBoundaries(String target, BreakIterator iterator) {
    StringBuffer markers = new StringBuffer();
    markers.setLength(target.length() + 1);
    for (int k = 0; k < markers.length(); k++) {
        markers.setCharAt(k,' ');
    }
    iterator.setText(target);
    int boundary = iterator.first();
    while (boundary != BreakIterator.DONE) {
        markers.setCharAt(boundary,'^');
        boundary = iterator.next();
    }
    System.out.println(target);
    System.out.println(markers);
}

markBoundaries方法的输出如下。请注意插入符号(^)相对于标点符号和空格的位置:

She stopped.  She said, "Hello there," and then
^  ^^      ^^ ^  ^^   ^^^^    ^^    ^^^^  ^^   ^
went on.
^   ^^ ^^

BreakIterator类使得从文本中选择单词变得容易。您不必编写自己的处理各种语言标点规则的例程;BreakIterator类会为您处理这些。

以下示例中的extractWords方法提取并打印给定字符串的单词。请注意,该方法使用Character.isLetterOrDigit来避免打印包含空格字符的“单词”。

static void extractWords(String target, BreakIterator wordIterator) {
    wordIterator.setText(target);
    int start = wordIterator.first();
    int end = wordIterator.next();
    while (end != BreakIterator.DONE) {
        String word = target.substring(start,end);
        if (Character.isLetterOrDigit(word.charAt(0))) {
            System.out.println(word);
        }
        start = end;
        end = wordIterator.next();
    }
}

BreakIteratorDemo程序调用extractWords,将其传递给前面示例中使用的相同目标字符串。extractWords方法打印出以下单词列表:

She
stopped
She
said
Hello
there
and
then
went
on

句子边界

原文:docs.oracle.com/javase/tutorial/i18n/text/sentence.html

你可以使用BreakIterator来确定句子边界。首先通过getSentenceInstance方法创建一个BreakIterator

BreakIterator sentenceIterator =
    BreakIterator.getSentenceInstance(currentLocale);

为了显示句子边界,程序使用了markBoundaries方法,该方法在单词边界一节中有讨论。markBoundaries方法在字符串下方打印插入符号(^)来指示边界位置。以下是一些示例:

She stopped.  She said, "Hello there," and then went on.
^             ^                                         ^
He's vanished!  What will we do?  It's up to us.
^               ^                 ^             ^
Please add 1.5 liters to the tank.
^    

行边界

原文:docs.oracle.com/javase/tutorial/i18n/text/line.html

应用程序格式化文本或执行换行操作必须找到潜在的换行位置。您可以使用使用getLineInstance方法创建的BreakIterator来找到这些换行位置或边界:

BreakIterator lineIterator =
    BreakIterator.getLineInstance(currentLocale);

这个BreakIterator确定字符串中文本可以断开以继续到下一行的位置。BreakIterator检测到的位置是潜在的换行位置。在屏幕上显示的实际换行可能不同。

接下来的两个示例使用BreakIteratorDemo.javamarkBoundaries方法来显示BreakIterator检测到的行边界。markBoundaries方法通过在目标字符串下方打印插入符号(^)来指示行边界。

根据BreakIterator,在一系列空格字符(空格、制表符、换行符)的终止后发生行边界。在下面的示例中,请注意您可以在检测到的任何边界处断开行:

She stopped.  She said, "Hello there," and then went on.
^   ^         ^   ^     ^      ^     ^ ^   ^    ^    ^  ^

潜在的换行位置也会在连字符后立即发生:

There are twenty-four hours in a day.
^     ^   ^      ^    ^     ^  ^ ^   ^

下一个示例将长文本字符串分成固定长度的行,使用名为formatLines的方法。该方法使用BreakIterator来定位潜在的换行位置。formatLines方法简短、简单,并且由于使用了BreakIterator,与语言环境无关。以下是源代码:

static void formatLines(
    String target, int maxLength,
    Locale currentLocale) {
    BreakIterator boundary = BreakIterator.
        getLineInstance(currentLocale);
    boundary.setText(target);
    int start = boundary.first();
    int end = boundary.next();
    int lineLength = 0;
    while (end != BreakIterator.DONE) {
        String word = target.substring(start,end);
        lineLength = lineLength + word.length();
        if (lineLength >= maxLength) {
            System.out.println();
            lineLength = word.length();
        }
        System.out.print(word);
        start = end;
        end = boundary.next();
    }
}

BreakIteratorDemo程序调用formatLines方法如下:

String moreText =
    "She said, \"Hello there,\" and then " +
    "went on down the street. When she stopped " +
    "to look at the fur coats in a shop + "
    "window, her dog growled. \"Sorry Jake,\" " +
    "she said. \"I didn't know you would take " +
    "it personally.\"";
formatLines(moreText, 30, currentLocale);

调用formatLines的输出为:

She said, "Hello there," and
then went on down the
street. When she stopped to
look at the fur coats in a
shop window, her dog
growled. "Sorry Jake," she
said. "I didn't know you
would take it personally."

将拉丁数字转换为其他 Unicode 数字

原文:docs.oracle.com/javase/tutorial/i18n/text/shapedDigits.html

默认情况下,当文本包含数字值时,这些值将使用拉丁(欧洲)数字显示。如果希望使用其他 Unicode 数字形状,请使用java.awt.font.NumericShaper类。NumericShaper API 使您能够以任何 Unicode 数字形状显示内部表示为 ASCII 值的数字值。

下面的代码片段来自ArabicDigits示例,展示了如何使用NumericShaper实例将拉丁数字转换为阿拉伯数字。确定整形操作的行已加粗。

ArabicDigitsPanel(String fontname) {
    HashMap map = new HashMap();
    Font font = new Font(fontname, Font.PLAIN, 60);
    map.put(TextAttribute.FONT, font);
    map.put(TextAttribute.NUMERIC_SHAPING,
        NumericShaper.getShaper(NumericShaper.ARABIC));
    FontRenderContext frc = new FontRenderContext(null, false, false);
    layout = new TextLayout(text, map, frc);
}
// ...
public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    layout.draw(g2d, 10, 50);
}

获取阿拉伯数字的NumericShaper实例,并将其放入HashMap中,用于TextLayout.NUMERIC_SHAPING属性键。哈希映射传递给TextLayout实例。在paint方法中呈现文本后,数字以所需脚本显示。在此示例中,拉丁数字 0 到 9 以阿拉伯数字形式显示。


前面的示例使用NumericShaper.ARABIC常量来检索所需的整形器,但NumericShaper类为许多语言提供了常量。这些常量被定义为位掩码,并称为NumericShaper 基于位掩码的常量

Java 中文官方教程 2022 版(三十)(3)https://developer.aliyun.com/article/1487965

相关文章
|
3天前
|
Web App开发 Java 测试技术
《手把手教你》系列技巧篇(五十六)-java+ selenium自动化测试-下载文件-上篇(详细教程)
【5月更文挑战第20天】本文介绍了自动化测试中如何实现无弹窗下载文件,主要针对Firefox浏览器。作者指出,通常的下载操作包括点击下载按钮,但这里讨论的是避免下载弹窗直接保存文件的方法。文章详细讲解了通过设置Firefox参数(如`browser.download.dir`、`browser.helperApps.neverAsk.saveToDisk`等)来实现这一功能,并给出了Java Selenium的示例代码,展示了如何创建FirefoxProfile并进行相关设置,以及如何启动浏览器和执行下载操作。
16 0
《手把手教你》系列技巧篇(五十六)-java+ selenium自动化测试-下载文件-上篇(详细教程)
|
8天前
|
机器学习/深度学习 移动开发 测试技术
《手把手教你》系列技巧篇(五十一)-java+ selenium自动化测试-字符串操作-下篇(详解教程)
【5月更文挑战第15天】自动化测试中进行断言的时候,我们可能经常遇到的场景。从一个字符串中找出一组数字或者其中的某些关键字,而不是将这一串字符串作为结果进行断言。这个时候就需要我们对字符串进行操作,宏哥这里介绍两种方法:正则和字符串切片函数split()。
25 2
|
2天前
|
Web App开发 Java 测试技术
《手把手教你》系列技巧篇(五十七)-java+ selenium自动化测试-下载文件-下篇(详细教程)
【5月更文挑战第21天】本文介绍了自动化测试中如何实现无弹窗下载文件,特别针对Chrome浏览器。通过设置`download.default_directory`和`profile.default_content_settings.popups`,可以避免下载弹窗并指定下载路径。示例代码展示了如何使用Java和Selenium实现这一功能,包括导入相关库、设置ChromeOptions和执行下载操作。最后,文章提到虽然没有介绍IE浏览器的下载方法,但已有Chrome和Firefox的方法已足够应对大多数需求。
17 0
|
3天前
|
Java 编译器
<JAVA> java入门面向0基础教程(数据类型,运算符)
<JAVA> java入门面向0基础教程(数据类型,运算符)
10 1
<JAVA> java入门面向0基础教程(数据类型,运算符)
|
3天前
|
Java 测试技术 API
《手把手教你》系列技巧篇(五十五)-java+ selenium自动化测试-上传文件-下篇(详细教程)
【5月更文挑战第19天】本文介绍了在Web自动化中处理文件上传的挑战,由于Selenium WebDriver不直接支持文件上传,因此需要借助外部工具。文章提到了两种主要的上传方式:基于input框的上传和非input控件的上传。对于非input控件的上传,推荐使用AutoIt,这是一个支持Windows GUI自动化的工具。
33 9
|
5天前
|
Web App开发 机器人 Java
《手把手教你》系列技巧篇(五十四)-java+ selenium自动化测试-上传文件-中篇(详细教程)
【5月更文挑战第18天】本文介绍了在Web自动化测试中处理文件上传的几种方法,特别是针对非`input`控件上传的场景。由于Selenium WebDriver无法操作系统级窗口,因此不能直接支持文件上传。作者提到了四种解决策略:AutoIT、Python的pywin32库、SendKeys库和keybd_event。文章以Java为例,详细阐述了使用Robot类模拟键盘操作来实现非`input`控件的文件上传,包括代码示例和实际项目中的应用。最后,作者分享了一个使用Python和Robot类处理百度图片搜索上传图片的实战案例,并指出有时Chrome浏览器可能需要特定条件才能成功模拟上传。
12 2
|
6天前
|
前端开发 JavaScript 测试技术
《手把手教你》系列技巧篇(五十三)-java+ selenium自动化测试-上传文件-上篇(详细教程)
【5月更文挑战第17天】本文介绍了在Web自动化测试中处理文件上传操作的方法。Selenium的WebDriver未提供直接的API来处理文件上传,因为这涉及到操作系统级别的窗口交互,而WebDriver无法识别非Web元素。文件上传主要分为两类:基于input控件的上传和非input控件的上传。对于input控件,可以直接使用sendKeys()方法输入文件的绝对路径来模拟选择文件。在项目实战中,给出了一个简单的HTML页面和对应的Java代码示例,展示了如何使用Selenium选取并上传文件。
18 0
|
7天前
|
JavaScript 前端开发 Java
《手把手教你》系列技巧篇(五十二)-java+ selenium自动化测试-处理面包屑(详细教程)
【5月更文挑战第16天】本文介绍了网页面包屑导航的概念、作用及其实现方式。面包屑导航是一种用户界面元素,帮助用户理解他们在网站中的位置并方便返回。通常形式为“首页>分类>子分类>内容页”,最多三层结构。在自动化测试中,处理面包屑涉及获取层级关系和当前层级,可以通过查找包含面包屑的div或ul元素,再提取其中的链接来实现。文中还提供了一个基于HTML和JavaScript的简单示例,并展示了相应的自动化测试代码设计和运行结果。
15 0
|
9天前
|
搜索推荐 Java 测试技术
《手把手教你》系列技巧篇(五十)-java+ selenium自动化测试-字符串操作-上篇(详解教程)
【5月更文挑战第14天】本文介绍了自动化测试中如何从字符串中提取特定信息,主要讲解了两种方法:正则表达式和字符串切片操作。文章提供了一个测试场景,即在搜索引擎中搜索“北京宏哥”并比较百度和必应的搜索结果数量。通过字符串切片函数`split()`,可以从搜索结果的描述中提取出数字。代码示例展示了如何使用Java实现这个功能,包括在百度和必应的搜索页面获取结果数量,并进行比较。文章最后还简单提到了其他字符串截取的方法,如`substring()`和`StringUtils`类中的方法。
24 2
|
10天前
|
JavaScript 前端开发 Java
《手把手教你》系列技巧篇(四十九)-java+ selenium自动化测试-隐藏元素定位与操作(详解教程)
【5月更文挑战第13天】本文主要讨论了在Selenium自动化测试中如何处理前端隐藏元素的问题。隐藏元素通常是通过`type="hidden"`或`style="display: none;"`属性实现的,它们在页面上不可见,但仍然存在于HTML代码中。Selenium可以定位到这些隐藏元素,但无法直接进行点击、输入等操作,会报错“ElementNotInteractableException”。
34 3