gpt4 book ai didi

unicode - NFC 标准化边界是否也扩展了字素簇边界?

转载 作者:行者123 更新时间:2023-12-04 11:28:15 26 4
gpt4 key购买 nike

这个问题与文本编辑有关。假设您在 normalization form 中有一段文字NFC,以及指向本文中扩展字素簇边界的光标。您想在光标位置插入另一段文本,并确保生成的文本也在 NFC 中。您还希望将光标移动到紧跟在插入文本之后的第一个字素边界上。
现在,由于连接两个都在 NFC 中的字符串不一定会生成也在 NFC 中的字符串,因此您可能需要修改插入点周围的文本。例如,如果您有一个包含 4 个代码点的字符串,如下所示:

[0] LATIN SMALL LETTER B
[1] LATIN SMALL LETTER E
[2] COMBINING MACRON BELOW
--- Cursor location
[3] LATIN SMALL LETTER A
并且您想插入一个 2-codepoints 字符串 {COMBINING ACUTE ACCENT, COMBINING DOT ABOVE}在光标位置。那么结果将是:
[0] LATIN SMALL LETTER B
[1] LATIN SMALL LETTER E WITH ACUTE
[2] COMBINING MACRON BELOW
[3] COMBINING DOT ABOVE
--- Cursor location
[4] LATIN SMALL LETTER A
现在我的问题是:在插入字符串后,您如何确定应该将光标放置在哪个偏移量处,从而使光标在插入的字符串之后结束并位于字素边界上?在这种特殊情况下,在标准化期间,光标位置后面的文本不可能与前面的文本交互。因此,以下示例 Python 代码将起作用:
import unicodedata

def insert(text, cursor_pos, text_to_insert):
new_text = text[:cursor_pos] + text_to_insert
new_text = unicodedata.normalize("NFC", new_text)
new_cursor_pos = len(new_text)
new_text += text[cursor_pos:]
if new_cursor_pos == 0:
# grapheme_break_after is a function that
# returns the offset of the first grapheme
# boundary after the given index
new_cursor_pos = grapheme_break_after(new_text, 0)
return new_text, new_cursor_pos

但是这种方法一定有效吗?更明确地说:在规范化过程中,遵循字素边界的文本是否一定不会与前面的文本交互,例如 NFC(text[:grapheme_break]) + NFC(text[grapheme_break:]) == NFC(text)总是真的吗?
更新
@nwellnhof 下面的出色分析促使我进行调查
更远。所以我遵循了“当有疑问时,使用蛮力”的口头禅并写了一个
解析字形中断属性并检查每个代码点的小脚本
可以出现在字素的开头,以测试它是否可以
可能在规范化期间与前面的代码点交互。这是
脚本:
from urllib.request import urlopen
import icu, unicodedata

URL = "http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt"

break_props = {}

with urlopen(URL) as f:
for line in f:
line = line.decode()
p = line.find("#")
if p >= 0:
line = line[:p]
line = line.strip()
if not line:
continue
fields = [x.strip() for x in line.split(";")]
codes = [int(x, 16) for x in fields[0].split("..")]
if len(codes) == 2:
start, end = codes
else:
assert(len(codes) == 1)
start, end = codes[0], codes[0]
category = fields[1]
break_props.setdefault(category, []).extend(range(start, end + 1))

# The only code points that can't appear at the beginning of a grapheme boundary
# are those that appear in the following categories. See the regexps in
# UAX #29 Tables 1b and 1c.
to_ignore = set(c for name in ("Extend", "ZWJ", "SpacingMark") for c in break_props[name])

nfc = icu.Normalizer2.getNFCInstance()
for c in range(0x10FFFF + 1):
if c in to_ignore:
continue
if not nfc.hasBoundaryBefore(chr(c)):
print("U+%04X %s" % (c, unicodedata.name(chr(c))))
查看输出,似乎有大约 40 个代码点是
字素初学者,但仍与前面的 NFC 代码点组合。
基本上,它们是类型为 V 的非预组合韩文音节。
(U+1161..U+1175) 和 T (U+11A8..U+11C2)。当你检查时,事情是有道理的
UAX #29, Table1c 中的正则表达式和什么一起
标准说明了 Jamo 组合( section 3.12, p. 147 of the version13 of the standard )。
其要点是形式为 {L, V} 的韩文序列可以组成一个 LV 类型的韩文音节, 以及类似 {LV, T} 形式的序列能够
组成 LVT 类型的音节.
总结一下,假设我没记错的话,上面的 Python 代码可以
更正如下:
import unicodedata
import icu # pip3 install icu

def insert(text, cursor_pos, text_to_insert):
new_text = text[:cursor_pos] + text_to_insert
new_text = unicodedata.normalize("NFC", new_text)
new_cursor_pos = len(new_text)
new_text += text[cursor_pos:]
new_text = unicodedata.normalize("NFC", new_text)
break_iter = icu.BreakIterator.createCharacterInstance(icu.Locale())
break_iter.setText(new_text)
if new_cursor_pos == 0:
# Move the cursor to the first grapheme boundary > 0.
new_cursor_pos = breakIter.nextBoundary()
elif new_cursor_pos > len(new_text):
new_cursor_pos = len(new_text)
elif not break_iter.isBoundary(new_cursor_pos):
# isBoundary() moves the cursor on the first boundary >= the given
# position.
new_cursor_pos = break_iter.current()
return new_text, new_cursor_pos
(可能)毫无意义的测试 new_cursor_pos > len(new_text)有去吗
抓案 len(NFC(x)) > len(NFC(x + y)) .我不确定这是否可以
实际发生在当前的 Unicode 数据库中(需要更多的测试来证明),但理论上很有可能。如果,说,你有
一套三码点 A , BC和两个预组合形式 A+BA+B+C (但不是 A+C ),那么你很可能拥有 NFC({A, C} + {B}) = {A+B+C} .
如果这种情况在实践中没有发生(这很有可能,尤其是在
“真实”文本),那么上面的 Python 代码一定会定位到第一个
插入文本结束后的字形边界。否则只会
在插入的文本之后定位一些字形边界,但不一定是
第一。我还没有看到如何改进第二种情况(假设它不仅仅是理论上的),所以我想我会离开
我现在对此的调查。

最佳答案

正如我在评论中提到的,实际边界可能略有不同。但是 AFAICS,应该没有有意义的交互。 UAX #29状态:

6.1 Normalization

[...] the grapheme cluster boundary specification has the following features:

  • There is never a break within a sequence of nonspacing marks.
  • There is never a break between a base character and subsequent nonspacing marks.

这仅提及非空格标记。但是对于扩展的字素集群(与传统的相反),我很确定这些陈述也适用于“非入门”间距标记[1]。这将涵盖所有标准化非启动项(必须是非间距 (Mn) 或间距 (Mc) 标记)。 因此,在非初学者[2] 之前,永远不会有扩展的字形集群边界。这应该给你你需要的保证。
请注意,在单个字形集群中可能有多个启动器和非启动器(“标准化边界”)运行,例如使用 U+034F COMBINING GRAPHEME JOINER。
[1] 一些间距标记 are excluded ,但这些都应该是初学者。
[2] 除了在文本的开头。

关于unicode - NFC 标准化边界是否也扩展了字素簇边界?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66693488/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com