作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题与文本编辑有关。假设您在 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)
总是真的吗?
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 个代码点是
V
的非预组合韩文音节。
T
(U+11A8..U+11C2)。当你检查时,事情是有道理的
{L, V}
的韩文序列可以组成一个
LV
类型的韩文音节, 以及类似
{LV, T}
形式的序列能够
LVT
类型的音节.
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))
.我不确定这是否可以
A
,
B
和
C
和两个预组合形式
A+B
和
A+B+C
(但不是
A+C
),那么你很可能拥有
NFC({A, C} + {B}) = {A+B+C}
.
最佳答案
正如我在评论中提到的,实际边界可能略有不同。但是 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.
关于unicode - NFC 标准化边界是否也扩展了字素簇边界?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66693488/
我是一名优秀的程序员,十分优秀!