【问题标题】:Python: Replace typographical quotes, dashes, etc. with their ascii counterpartsPython:用对应的 ascii 替换印刷引号、破折号等
【发布时间】:2012-04-24 08:04:45
【问题描述】:

人们可以在我的网站上发布新闻,并且很多编辑使用 MS Word 和类似工具来编写文本,然后复制并粘贴到我网站的编辑器中(简单的文本区域,没有所见即所得等)。

这些文本通常包含“漂亮”的引号,而不是普通的 ascii 引号 (")。它们有时还包含那些较长的破折号,例如 而不是 -

现在我想用对应的 ascii 替换所有这些字符。但是,我不想删除变音符号和其他非 ascii 字符。我也非常喜欢使用不涉及为所有这些字符创建映射字典的适当解决方案。

我所有的字符串都是 unicode 对象。

【问题讨论】:

  • 为什么不只使用 unicode(我知道你知道这是一个选项)?此外,还有一个可混淆字符的官方 unicode 列表,如果您必须自己滚动,可能会有所帮助。
  • 我确实使用 UTF8/unicode。有些人使用 textarea 来编写他们的内容,所以现在我混合了引号/破折号样式,这取决于谁写了一些相当丑陋的东西。
  • 嗯,我正在寻找可以使“那些东西”正常化的东西。在 markdown=>html 转换之前或之后完成都没有关系。我非常喜欢之前这样做,但从那时起我可以将正确规范化的字符串存储在我的数据库中。
  • 很高兴知道您最终对此做了什么。
  • 更好地定义“适当的解决方案”。映射字典是标准库中类似函数的编码方式。这不是漂亮的代码,因为它不是一个漂亮的问题。

标签: python string


【解决方案1】:

这个呢? 它首先创建翻译表,但老实说,我认为没有它你就无法做到这一点。

transl_table = dict( [ (ord(x), ord(y)) for x,y in zip( u"‘’´“”–-",  u"'''\"\"--") ] ) 

with open( "a.txt", "w", encoding = "utf-8" ) as f_out : 
    a_str = u" ´funny single quotes´ long–-and–-short dashes ‘nice single quotes’ “nice double quotes”   "
    print( " a_str = " + a_str, file = f_out )

    fixed_str = a_str.translate( transl_table )
    print( " fixed_str = " + fixed_str, file = f_out  )

我无法将此打印运行到控制台(在 Windows 上),因此我必须写入 txt 文件。
a.txt 文件中的输出如下所示:

a_str = 'funny single quotes' long--and--short dashes 'nice single 引号' “漂亮的双引号” fixed_str = '有趣的单引号' 长短破折号“漂亮的单引号”“漂亮的双引号”

顺便说一句,上面的代码在 Python 3 中工作。如果您需要它用于 Python 2,由于两种语言版本中处理 Unicode 字符串的差异,它可能需要一些修复

【讨论】:

    【解决方案2】:

    没有这样的“正确”解决方案,因为对于任何给定的 Unicode 字符,都没有定义“ASCII 对应物”。

    例如,将看似简单的字符映射到 ASCII 单引号、双引号和连字符。首先,让我们生成所有带有官方名称的 Unicode 字符。其次,让我们根据名称查找所有引号、连字符和破折号:

    #!/usr/bin/env python3
    
    import unicodedata
    
    def unicode_character_name(char):
        try:
            return unicodedata.name(char)
        except ValueError:
            return None
    
    # Generate all Unicode characters with their names
    all_unicode_characters = []
    for n in range(0, 0x10ffff):    # Unicode planes 0-16
        char = chr(n)               # Python 3
        #char = unichr(n)           # Python 2
        name = unicode_character_name(char)
        if name:
            all_unicode_characters.append((char, name))
    
    # Find all Unicode quotation marks
    print (' '.join([char for char, name in all_unicode_characters if 'QUOTATION MARK' in name]))
    # " « » ‘ ’ ‚ ‛ “ ” „ ‟ ‹ › ❛ ❜ ❝ ❞ ❟ ❠ ❮ ❯ ⹂ 〝 〞 〟 " ? ? ?
    
    # Find all Unicode hyphens
    print (' '.join([char for char, name in all_unicode_characters if 'HYPHEN' in name]))
    # - ­ ֊ ᐀ ᠆ ‐ ‑ ‧ ⁃ ⸗ ⸚ ⹀ ゠ ﹣ - ?
    
    # Find all Unicode dashes
    print (' '.join([char for char, name in all_unicode_characters if 'DASH' in name and 'DASHED' not in name]))
    # ‒ – — ⁓ ⊝ ⑈ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ╌ ╍ ╎ ╏ ⤌ ⤍ ⤎ ⤏ ⤐ ⥪ ⥫ ⥬ ⥭ ⩜ ⩝ ⫘ ⫦ ⬷ ⸺ ⸻ ⹃ 〜 〰 ︱ ︲ ﹘ ?
    

    如您所见,尽管这个示例很简单,但存在很多问题。 Unicode 中有许多引号与 US-ASCII 中的引号完全不同,而 Unicode 中有许多连字符与 US-ASCII 中的连字符减号完全不同。

    还有很多问题。例如:

    • 应将“SWUNG DASH”(⁓) 符号替换为 ASCII 连字符 (-) 还是波浪号 (~)?
    • 应将“加拿大音节连字符”(᐀) 替换为 ASCII 连字符 (-) 还是等号 (=)?
    • 应该用 ASCII 引号 (")、撇号 (') 还是小于号 (

    要建立“正确”的 ASCII 对应物,需要有人根据使用上下文回答这些问题。这就是为什么您的问题的所有解决方案都以一种或另一种方式基于映射字典。所有这些解决方案都会提供不同的结果。

    【讨论】:

      【解决方案3】:

      您可以在 unidecode 包的基础上进行构建。

      这很慢,因为我们首先将所有 unicode 标准化为组合形式,然后尝试查看 unidecode 将其转换为什么。如果我们匹配一个拉丁字母,那么我们实际上使用的是原始 NFC 字符。如果不是,那么我们会产生任何 degarbling unidecode 建议的内容。这只会留下强调字母,但会转换其他所有内容。

      import unidecode
      import unicodedata
      import re
      
      def char_filter(string):
          latin = re.compile('[a-zA-Z]+')
          for char in unicodedata.normalize('NFC', string):
              decoded = unidecode.unidecode(char)
              if latin.match(decoded):
                  yield char
              else:
                  yield decoded
      
      def clean_string(string):
          return "".join(char_filter(string))
      
      print(clean_string(u"vis-à-vis “Beyoncé”’s naïve papier–mâché résumé"))
      # prints vis-à-vis "Beyoncé"'s naïve papier-mâché résumé
      

      【讨论】:

      • 这个解决方案最终是一个大的映射字典。而且那里的一些映射决定是不寻常的。例如,它将破折号 (-) 映射到两个连字符 (--)。
      【解决方案4】:

      您可以使用 str.translate() 方法 (http://docs.python.org/library/stdtypes.html#str.translate)。但是,阅读与 Unicode 相关的文档——翻译表有另一种形式:unicode ordinal number --> unicode string (通常是 char) 或 None。

      嗯,但它需要字典。无论如何,您必须捕获替代品。如果没有任何表或数组,你想如何做到这一点?您可以将 str.replace() 用于单个字符,但这会效率低下。

      【讨论】:

      • 我希望有一些聪明的方法可以只翻译非字母的字符。
      【解决方案5】:

      此工具将标准化 Markdown 中的标点符号:http://johnmacfarlane.net/pandoc/README.html

      -S, --smart 生成印刷正确的输出,将直引号转换为弯引号,--- 转换为 em-dashes,--转换为 en-dashes, 和 ... 到椭圆。在某些之后插入不间断空格 缩写,例如“先生” (注:此选项仅重要 当输入格式为 markdown 或 Textile 时。它被选中 当输入格式为 Textile 或输出格式为 乳胶或上下文。)

      它是haskell,所以你必须弄清楚接口。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-09
        • 1970-01-01
        • 2011-03-08
        • 2012-07-07
        • 2011-08-28
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        相关资源
        最近更新 更多