Unicode 使用(核心)基础折叠/规范化连接(例如,至ae)
我正在编写一个助手,它对输入字符串执行许多转换,以便创建该字符串的搜索友好表示形式 考虑以下场景:Unicode 使用(核心)基础折叠/规范化连接(例如,至ae),unicode,transform,core-foundation,foundation,Unicode,Transform,Core Foundation,Foundation,我正在编写一个助手,它对输入字符串执行许多转换,以便创建该字符串的搜索友好表示形式 考虑以下场景: 德语或法语文本的全文搜索 数据存储中的条目包含 Müller Großmann chiingletòn Bjørk Æreograme 在这种情况下,搜索应该是模糊的 ull,ll等匹配Müller Gros,groß等匹配großmann cin等匹配chiingletòn bjö,bjo等。匹配bjørk aereo等匹配Æreograme 到目前为止,我在案例(1)、(3)和(4)中
- 德语或法语文本的全文搜索
- 数据存储中的条目包含
Müller
Großmann
chiingletòn
Bjørk
Æreograme
- 在这种情况下,搜索应该是模糊的
,ull
等匹配ll
Müller
,Gros
等匹配groß
großmann
等匹配cin
chiingletòn
,bjö
等。匹配bjo
bjørk
等匹配aereo
Æreograme
CFStringNormalize() // with all documented normalization forms
CFStringTransform() // using the kCFStringTransformToLatin, kCFStringTransformStripCombiningMarks, kCFStringTransformStripDiacritics
CFStringFold() // using kCFCompareNonliteral, kCFCompareWidthInsensitive, kCFCompareLocalized in a number of combinations -- aside: how on earth do I normalize simply _composing_ already decomposed strings??? as soon as I pack that in, my formerly passing tests fail, as well...
我略读了一遍,但没有在上面投入太多,原因很明显
我知道我可以通过转换成大写然后再转换回小写来捕获大小写(2),这将在这个特定应用程序的领域内工作。然而,我对从更基本的层面解决这个问题感兴趣,希望也能考虑区分大小写的应用程序
任何提示都将不胜感激 祝贺你,你发现了文本处理中最痛苦的一点 首先,如果你还没有看过的话,它们是这类事情不可或缺的资源 问题的一部分在于,您试图做一些几乎正确的事情,这些事情适用于您所关心的所有语言/区域设置,而Unicode更关心的是在单一语言区域设置中显示字符串时做正确的事情 对于(2),
ß
从我能找到的最早的CaseFolding.txt()起,就被规范地折叠为ss
CFStringFold()
和-[NSString stringByFoldingWithOptions:
应该做正确的事情,但如果做不到这一点,一个“与语言环境无关的”s.upper().lower()
似乎为所有输入提供了一个合理的答案(并且还处理臭名昭著的“Turkish I”)
对于(5),您的运气有点不好:Unicode 6.2似乎不包含从Æ到AE的规范映射,并且从“字母”到“连字”再到(U+00C6在1.0中是拉丁大写字母AE
,在1.1中是拉丁大写连字AE
,在2.0中是拉丁大写字母AE
)。您可以在NamesList.txt中搜索“ligature”,并添加一些特殊情况
注:
不执行您想要的操作。您确实希望在将字符串添加到索引之前对其进行规范化;我建议在其他处理的开始和结束时使用NFKCCFStringNormalize()
也不能完全满足您的需要;所有脚本都是“拉丁语”CFStringTransform()
取决于顺序:组合由CFStringFold()
剥离,但由kCFCompareDiacriticInsensitive
转换为小写iota。“正确”的做法似乎是先折叠案例,然后再折叠其他案例,尽管从语言学角度来说,将其剥离可能更有意义KCFCompareCaseCensitive
- 您几乎肯定不想使用
,除非您希望在每次区域设置更改时重新生成搜索索引kCFCompareLocalized
其他语言的读者注意:检查您使用的函数是否不依赖于用户当前的语言环境!Java用户应该使用类似于
s.toUpperCase(Locale.ENGLISH)
,.NET用户应该使用s.ToUpperInvariant()
。如果您确实需要用户的当前区域设置,请显式指定它。我在字符串上使用了以下扩展,它似乎工作得很好
/// normalized version of string for comparisons and database lookups. If normalization fails or results in an empty string, original string is returned.
var normalized: String? {
// expand ligatures and other joined characters and flatten to simple ascii (æ => ae, etc.) by converting to ascii data and back
guard let data = self.data(using: String.Encoding.ascii, allowLossyConversion: true) else {
print("WARNING: Unable to convert string to ASCII Data: \(self)")
return self
}
guard let processed = String(data: data, encoding: String.Encoding.ascii) else {
print("WARNING: Unable to decode ASCII Data normalizing stirng: \(self)")
return self
}
var normalized = processed
// // remove non alpha-numeric characters
normalized = normalized.replacingOccurrences(of: "?", with: "") // educated quotes and the like will be destroyed by above data conversion
// strip appostrophes
normalized = normalized.replacingCharacters(in: "'", with: "")
// replace non-alpha-numeric characters with spaces
normalized = normalized.replacingCharacters(in: CharacterSet.alphanumerics.inverted, with: " ")
// lowercase string
normalized = normalized.lowercased()
// remove multiple spaces and line breaks and tabs and trim
normalized = normalized.whitespaceCollapsed
// may return an empty string if no alphanumeric characters! In this case, use the raw string as the "normalized" form
if normalized == "" {
return self
} else {
return normalized
}
}
+1太棒了!我已经得出结论,我永远也得不到这个问题的答案。我不再处理这个问题了,所以我需要一些时间来充分理解这个问题——我想我周末有点阅读要做!