断字

使用 Knuth-Liang 算法实现高效且灵活的自动断字。

请参阅完整文档:https://john-mueller.github.io/Hyphenation

目录

简介

此库的主要目的是自动在文本中插入软连字符,以改善其布局流程。请参考 Butterick's Practical Typography 中的以下示例。

Text without hyphenation

随着行长的缩短,对齐的文本通常会在单词之间显示较大的间隙,而左对齐或右对齐的文本则显示越来越不均匀的边距。通过在单词中插入软连字符(仅在单词位于行尾时显示),可以将文本更自然地拆分为多行,从而改善文本的美观性。

Text with hyphenation

这在 HTML 中非常有用(因为 hyphens CSS 属性 并非普遍支持),甚至可以在 UIKit 和 SwiftUI 文本组件中使用。

安装

通过 Swift Package Manager 安装断字。首先,将其添加到您的依赖项中。

let package = Package(
    ...
    dependencies: [
        .package(url: "https://github.com/john-mueller/Hyphenation.git", from: "0.2.0")
    ],
    ...
)

然后在需要的地方导入 Hyphenation 模块。

import Hyphenation

用法

基本用法只需要创建一个 Hyphenator 实例并调用其 hyphenate(text:) 方法。

let hyphenator = Hyphenator()
hyphenator.separator = "-"

let text = "This algorithm identifies likely hyphenation points."
print(hyphenator.hyphenate(text: text))
// This al-go-rithm iden-ti-fies like-ly hy-phen-ation points.

您还可以通过调用 unhyphenate(text:) 从字符串中删除 separator 字符。

let hyphenatedText = "This al-go-rithm iden-ti-fies like-ly hy-phen-ation points."
print(hyphenator.unhyphenate(text: hyphenatedText))
// This algorithm identifies likely hyphenation points.

请注意,如果原始字符串包含 separator 字符,则 unhyphenate(text:) 方法也会删除这些实例,因此断字和取消断字字符串可能无法恢复原始字符串。

例外

该算法旨在优先防止不正确的断字,而不是找到每一个正确的断字——错过一个断字很少对文本流程产生有意义的影响,但是错误的断字可能相当明显。由于模式是从英语字典中派生的,因此它可以对许多未出现在字典中的单词做出很好的猜测。

let hyphenator = Hyphenator()
hyphenator.separator = "-"

print(hyphenator.hyphenate(text: "swiftlang supercalifragilisticexpialidocious"))
// swift-lang su-per-cal-ifrag-ilis-tic-ex-pi-ali-do-cious

尽管如此,该算法有时可能会对品牌名称或其他不寻常的单词产生意外的结果。在这种情况下,您可以手动使用例外指定所需的断字。

print(hyphenator.hyphenate(text: "Microsoft sesquipedalian"))
// Mi-crosoft sesquipedalian

hyphenator.addCustomExceptions(["Micro-soft", "ses-qui-pe-da-li-an"])

print(hyphenator.hyphenate(text: "Microsoft sesquipedalian"))
// Micro-soft ses-qui-pe-da-li-an

要删除自定义例外,请使用以下方法。

hyphenator.removeCustomExceptions(["sesquipedalian"])
hyphenator.removeAllCustomExceptions()

可自定义的属性

您可以修改几个属性来调整单词的断字方式。

separator 属性设置在断字点插入的字符。 默认情况下,这是 U+00AD(软连字符)。

minLengthminLeadingminTrailing 属性调整分隔符字符可以插入到单词中的位置。

自定义模式

此库默认包含美式英语的断字模式,但您可以轻松地使用其他语言的模式初始化 Hyphenator 实例。模式可以通过 StringURL 传递。

let hyphenator1 = Hyphenator(patterns: patternsString, exceptions: exceptionsString)
let hyphenator2 = Hyphenator(patternFile: patternsURL, exceptions: exceptionsURL)

可以在 TeX 断字仓库中找到各种语言的模式。请在 TeX 断字模式网站上检查每组模式发布的许可。此页面还列出了每种语言的正确 minLeadingminTrailing

在初始化新的 Hyphenator 实例时,假定模式由换行符或空格分隔。

线程安全

Hyphenator 类是线程安全的,可以用于在多个线程上同时进行断字(尽管使用两个实例的性能优势可以忽略不计)。

copy() 方法提供了一种有效的方法来创建一个新的 Hyphenator 实例,该实例具有与现有实例相同的属性和模式。

HTML/代码

您不应将 hyphenate(text:) 方法直接应用于包含 HTML 或代码的字符串,因为代码元素可能会被错误地断字。更安全的方法是使用另一种能够识别 HTML 或代码元素并将断字仅应用于标记中的纯文本内容的工具。

有关使用 SwiftSoup 断字 HTML 的示例,请参见 HyphenationPublishPlugin

贡献

如果您在使用 Hyphenation 时遇到问题,请通过提交问题或提交 pull request 告诉我!

提交问题时,请尽最大努力提供可重现的步骤和对预期行为的解释。

如果是 pull request,请注意以下步骤:

  1. 在项目目录中运行时,swiftlint 不应产生任何警告。 这是由 CI 检查的,但我也建议尽可能在本地进行 lint(有关安装说明,请参见 SwiftLint 仓库)。
  2. 确保 make test 不会导致任何错误。 这将在 CorrectnessTestsThreadSafetyTests 文件中运行测试。
  3. 如果更改任何内部实现,请在进行更改前后运行 make bench,以检查是否存在任何速度回归。 这将在 PerformanceTests 文件中运行测试。

许可证

Hyphenation 在 MIT 许可下提供(请参见 LICENSE.md)。

英语断字模式在 原始自定义许可下提供,并且来自 TeX 断字仓库

用于性能测试的文本位于公共领域,并在其标头中注明。

简介中的示例段落来自 Butterick's Practical Typography,并经许可使用。

鸣谢

该库的灵感来自 Butterick's Practical Typography 中关于对齐文本可选连字符的页面,以及作者在 Racket 中的实现。 值得一读!