假设我有以下字符串:
s = 'Pingüino: Málaga es una ciudad fantástica y en Logroño me pica el... moño'
对于它是什么,我想删除所有波浪线和变音符号,使其看起来像:
s = 'Pinguino: Malaga es una ciudad fantastica y en Logroño me pica el... moño'
# ^ ^ ^
我发现了unidecode
正是这样做的库:
>>> unidecode.unidecode(s)
'Pinguino: Malaga es una ciudad fantastica y en Logrono me pica el... mono'
但不幸的是,它也将ñ替换为n(Logroño → Logrono,moño → mono)。
是否有任何其他库允许这种替换,只改变重音和变音符号?否则,我知道我必须做的是一个进行此修改的正则表达式。
技巧大体是一样的:就是在Unicode中取分解的规范化形式,去掉不想要的,返回复合形式。
分解形式??在 Unicode 中,一个字符(实际上是一个“字形”)被分解成它的基本字符等价物,然后是它的标记。例如:
分解的 (D) 和复合的 (C) 形式都是等价的(unicode canonical equivalence)。所以它们的字节不同,但它们打印相同
(它们仍然是相同的字素,并且有算法可以在形式之间进行比较)。
在NFD形式中,变音符号是与其基本字符(第一个代码点)分开的代码点......这是能够删除您不想要的内容的关键!并且消除后可以打印成那个表格(D),但是返回复合表格很方便,避免出现问题。
要删除什么?所有选项均有效。如果他们被理解,请根据适合您的情况进行选择,并且您更愿意在您的情况下申请。
ChemaCortes 在他的回答中选择删除所有非 ascii 字符(这就是他暂时
ñ
用另一个未删除的 ascii 字符串替换的原因)。FJSevilla 在其回应中将步枪直接对准重音符号(
´
)和变音符号(¨
)。有了基础,我就不得不选择展示最原教旨主义的选择:消灭所有变音符号。
删除除
ñ
所有变音符号都在范围内的一个块中
U+0300
-U+036F
(组合变音符号)。我们将例外U+0303
,波浪号 (~
),但是n
(替换其他像 aã
)ñ͚͡
)使用正则表达式,其中第一组是基本字符,变音符号在组外:
([^n\u0300-\u036f])[\u0300-\u036f]+
一个n
既不是 a 也不是变音符号的字符,后跟变音符号,或(n(?!\u0303(?![\u0300-\u036f])))[\u0300-\u036f]+
一个n
不跟随的~
(除非后者后面跟着另一个变音符号),那么它确实匹配它后面的所有变音符号。替换为
\1
we 留下没有变音符号的字母。代码
https://ideone.com/YcXaQD
从标准库中提取的另一个可能的想法
unicodedata
是获取 unicode 字符串的分解规范化形式。这允许"á"
从u"\u00E1"
到u"\u0061\u0301"
例如。然后简单地使用
str.translate
删除我们想要的 unicode 代码点,在这种情况下U+0308
(组合分音符号)和U+0301
(组合尖锐重音):在 Python 3 中,您可以简单地执行以下操作:
不幸的是,不是在 Python 2 或更早版本中,您还必须导入String模块才能使用string.maketrans(),并且在应用它时它会告诉您字符串 a 和 b 的长度不同,在事实len(a) = 12而len(b) = 6
“清理”字符串只需要标准库:
为防止 e 丢失,将它们替换为您知道不会使用的符号很简单: