【发布时间】:2013-06-13 22:36:57
【问题描述】:
在 Python 中从 unicode 字符串中去除字符修饰符的最简单方法是什么?
例如:
A͋͠r͍̞̫̜͌ͦ̈́͐ͅt̼̭͞h́u̡̙̞̘̙̬͖͓rͬͣ̐ͮͥͨ̀͏̣应该成为亚瑟
我尝试了文档,但找不到任何这样做的东西。
【问题讨论】:
在 Python 中从 unicode 字符串中去除字符修饰符的最简单方法是什么?
例如:
A͋͠r͍̞̫̜͌ͦ̈́͐ͅt̼̭͞h́u̡̙̞̘̙̬͖͓rͬͣ̐ͮͥͨ̀͏̣应该成为亚瑟
我尝试了文档,但找不到任何这样做的东西。
【问题讨论】:
试试这个
import unicodedata
a = u"STRING GOES HERE" # using an actual string would break stackoverflow's code formatting.
u"".join( x for x in a if not unicodedata.category(x).startswith("M") )
这将删除所有归类为标记的字符,这是我认为您想要的。一般来说,你可以通过unicodedata.category获取一个字符的类别。
【讨论】:
.startswith('M') 而不是'M' in。从 6.1 开始,没有任何类别的“M”子类别,但没有规定将来不能有。
M 类别的子类别,它将用于组合标记。如果添加了某个其他类别的新M 子类别,则不会用于组合标记。所以,组合标记的正确规则是cat.startswith('M'),而不是'M' in cat。 (不太可能出现那个,因为他们没有添加任何共享主要类别使用的字母的新子类别,并清空了唯一的现有子类别LC。但是没有什么坏处做正确的事,至少有潜在的好处。)
'M' in 将在未来工作,因为子类别将是'm',并且startswith 也将继续工作。 Startswith 更有意义,因为它总是第一个字符;除非类别名称发生根本性变化,否则情况将如此,在这种情况下,您几乎不能指望相同的代码可以工作。
您也可以使用regex module 支持的r'\p{M}':
import regex
def remove_marks(text):
return regex.sub(ur"\p{M}+", "", text)
例子:
>>> print s
A͋͠r͍̞̫̜t̼̭͞h́u̡̙̞̘rͬͣ̐ͮ
>>> def remove_marks(text):
... return regex.sub(ur"\p{M}+", "", text)
...
...
>>> print remove_marks(s)
Arthur
根据您的用例,白名单方法可能会更好,例如,将输入仅限于 ascii 字符:
>>> s.encode('ascii', 'ignore').decode('ascii')
u'Arthur'
结果可能取决于文本中使用的 Unicode 规范化。
【讨论】:
unicoredata.normalize('NFD', s).encode('ascii', 'ignore').decode('ascii') 来解决这个问题。 (您可能想使用 'NFKD' 代替,这取决于您是否希望得到 U+2160 (Ⅰ) 之类的东西,如果是的话,是否要将它们视为兼容的等效 U+0049 (I ) 或跳过它们。)