Python:Replace";“哑引号”;带有“;卷曲的”;一串

Python:Replace";“哑引号”;带有“;卷曲的”;一串,python,string,typography,Python,String,Typography,我有这样一个字符串: “但是那位先生,”看着达西,“似乎认为这个国家一无所有。” 我想要这个输出: “但是那位先生,”看着达西,“似乎认为这个国家一无所有。” 同样,哑单引号应该转换为它们的卷曲等价物 我的猜测是,这个问题以前已经解决了,但我找不到一个库或脚本来解决它。(Perl)是实现这一点的所有库之母,并且有一个简单的方法。但它的输出是HTML实体:“;但是那位先生,”我只想要一个带卷引号的普通字符串。有什么想法吗 更新: 我按照Padraig Cunningham的

我有这样一个字符串:

“但是那位先生,”看着达西,“似乎认为这个国家一无所有。” 我想要这个输出:

“但是那位先生,”看着达西,“似乎认为这个国家一无所有。” 同样,哑单引号应该转换为它们的卷曲等价物

我的猜测是,这个问题以前已经解决了,但我找不到一个库或脚本来解决它。(Perl)是实现这一点的所有库之母,并且有一个简单的方法。但它的输出是HTML实体:
“;但是那位先生,”我只想要一个带卷引号的普通字符串。有什么想法吗

更新:

我按照Padraig Cunningham的建议解决了这个问题:

  • 使用smartypants进行排版更正
  • 使用
    HTMLParser().unescape
    将HTML实体转换回Unicode
  • 如果您的输入文本包含您不希望转换的HTML实体,但在我的情况下没有问题,那么这种方法可能会有问题

    更新结束

    输入是否可信

    目前为止,只能信任输入。字符串可以包含一个非封闭的双引号:
    “但可以是那个绅士,看着Dary
    。它也可以包含一个非封闭的单引号:
    ”但可以是那个绅士,看着Dary
    。最后,它可以包含一个撇号:
    不要去那里。

    我已经实现了一个alogrithm,它试图正确地关闭这些丢失的引号,因此这不是问题的一部分。为了完整起见,下面是关闭丢失的引号的代码:

    quotationMarkDictionary = [{
        'start': '"',
        'end': '"',
        },{
        'start': '“',
        'end': '”',
        },{
        'start': '\'',
        'end': '\'',
        },{
        'start': '‘',
        'end': '’'
        },{
        'start': '(',
        'end': ')'
        },{
        'start': '{',
        'end': '}'
        },{
        'start': '[',
        'end': ']'
        }]
    
    '''If assumedSentence has quotation marks (single, double, …) and the 
    number of opening quotation marks is larger than the number of closing    
    quotation marks, append a closing quotation mark at the end of the 
    sentence. Likewise, add opening quotation marks to the beginning of the 
    sentence if there are more closing marks than opening marks.'''
    for quotationMark in quotationMarkDictionary:
      numberOpenings = assumedSentence['sentence'].count(quotationMark['start'])
      numberClosings = assumedSentence['sentence'].count(quotationMark['end'])
      # Are the opening and closing marks the same? ('Wrong' marks.) Then just make sure there is an even number of them
      if quotationMark['start'] is quotationMark['end'] and numberOpenings % 2 is not 0:
        # If sentence starts with this quotation mark, put the new one at the end
        if assumedSentence['sentence'].startswith(quotationMark['start']):
          assumedSentence['sentence'] += quotationMark['end']
        else:
          assumedSentence['sentence'] = quotationMark['end'] + assumedSentence['sentence']
      elif numberOpenings > numberClosings:
        assumedSentence['sentence'] += quotationMark['end']
      elif numberOpenings < numberClosings:
         assumedSentence['sentence'] = quotationMark['start'] + assumedSentence['sentence']
    
    quotationMarkDictionary=[{
    '开始':'''',
    "结束":"""结束",,
    },{
    '开始':'''',
    "结束":"""结束",,
    },{
    “开始”:“\”,
    “结束”:“结束”,
    },{
    '开始':'',
    '结束':'''
    },{
    '开始':'(',
    '结束':')'
    },{
    “开始”:“{”,
    “结束”:“}”
    },{
    “开始”:“[”,
    “结束”:“]”
    }]
    ''如果假设事件有引号(单引号、双引号,…),则
    开始引号的数量大于结束引号的数量
    引号,在结尾处附加一个结束引号
    同样,在句子的开头加上引号
    “如果结束标记多于开始标记,则判一句。”“
    对于quotationMarkDictionary中的quotationMark:
    NumberRopengs=假设事件['句子]。计数(引用标记['start'])
    numberClosings=假设事件['句子]。计数(引用标记['end'])
    #开始标记和结束标记相同吗?(“错误”标记)。然后确保有偶数个标记
    如果quotationMark['start']是quotationMark['end'],并且NumberRopengs%2不是0:
    #如果句子以这个引号开头,把新的放在末尾
    如果假设事件['SENTURE'].STARTSWITS(引用标记['start']):
    假设事件['SENTURE']+=quotationMark['end']
    其他:
    假设分数['SENTURE']=quotationMark['end']+假设分数['SENTURE']
    elif NumberRopings>numberClosings:
    假设事件['SENTURE']+=quotationMark['end']
    elif numberropings
    浏览文档,您似乎被
    卡住了。请在smartypants顶部更换

    smartypants(r'"smarty" \"pants\"').replace('&#x201C;', '“').replace('&#x201D;', '”')
    
    In [32]: from HTMLParser import HTMLParser
    
    In [33]: s = "&#x201C;But that gentleman,&#x201D;"
    
    In [34]: print HTMLParser().unescape(s)
    “But that gentleman,”
    In [35]: HTMLParser().unescape(s)
    Out[35]: u'\u201cBut that gentleman,\u201d'
    
    但是,如果您为魔术字符串添加别名,可能会读得更好:

    html_open_quote = '&#x201C;'
    html_close_quote = '&#x201D;'
    smart_open_quote = '“'
    smart_close_quote = '”'
    smartypants(r'"smarty" \"pants\"') \
        .replace(html_open_quote, smart_open_quote)  \
        .replace(html_close_quote, smart_close_quote)
    

    假设输入良好,则可以使用正则表达式完成此操作:

    # coding=utf8
    import re
    sample = '\'Sample Text\' - "But that gentleman," looking at Darcy, "seemed to think the \'country\' was nothing at all." \'Don\'t convert here.\''
    print re.sub(r"(\s|^)\'(.*?)\'(\s|$)", r"\1‘\2’\3", re.sub(r"\"(.*?)\"", r"“\1”", sample))
    
    输出:

    ‘Sample Text’ - “But that gentleman,” looking at Darcy, “seemed to think the ‘country’ was nothing at all.” ‘Don't convert here.’
    

    我在这里分离单引号,假设它们要么在一行的开头/结尾,要么周围有空格。

    您可以使用
    HTMLParser
    来取消显示从smartypants返回的html实体:

    smartypants(r'"smarty" \"pants\"').replace('&#x201C;', '“').replace('&#x201D;', '”')
    
    In [32]: from HTMLParser import HTMLParser
    
    In [33]: s = "&#x201C;But that gentleman,&#x201D;"
    
    In [34]: print HTMLParser().unescape(s)
    “But that gentleman,”
    In [35]: HTMLParser().unescape(s)
    Out[35]: u'\u201cBut that gentleman,\u201d'
    
    要避免编码错误,您应该在打开文件时使用
    io.open
    ,并指定
    encoding=“the_encoding”
    或将字符串解码为unicode:

     In [11]: s
    Out[11]: '&#x201C;But that gentleman,&#x201D;\xe2'
    
    In [12]: print  HTMLParser().unescape(s.decode("latin-1"))
    “But that gentleman,”â
    

    自从最初提出这个问题以来,Python smartypants在以Unicode直接输出替换字符方面获得了成功:

    u=256

    输出Unicode字符而不是数字字符引用,例如,从“到左双引号(”)(U+201C)


    对于最简单的可能用例,不需要正则表达式:

    # coding=utf8
    import re
    sample = '\'Sample Text\' - "But that gentleman," looking at Darcy, "seemed to think the \'country\' was nothing at all." \'Don\'t convert here.\''
    print re.sub(r"(\s|^)\'(.*?)\'(\s|$)", r"\1‘\2’\3", re.sub(r"\"(.*?)\"", r"“\1”", sample))
    
    quote\u chars\u计数={
    '"': 0,
    "'": 0,
    "`": 0
    }
    def至智能报价:
    输出=[]
    对于s中的c:
    如果quote_chars_中的c计数.keys():
    替换=(引用字符计数[c]%2==0)和''or''
    quote_chars_counts[c]=quote_chars_counts[c]+1
    新的=更换
    其他:
    new_ch=c
    output.append(新的)
    返回“”。连接(输出)
    

    如果需要,修改从替换映射中提取替换而不是使用文字是很简单的。

    到目前为止您尝试了什么?您对您的输入有多信任?引号总是成对出现吗?给您-@hashcode55这会生成HTML实体,而不是纯文本。@user158024我在帖子中添加了有关您的输入的信息questions.re.sub函数支持回调以进行替换,您可以在其中执行%2操作。我不确定我是否理解。您是否建议使用smartypants获取HTML实体,然后将这些实体解码回纯文本?好主意,但我遇到一个错误。在.Traceback之前,字符串已从.txt文件中读取(最近一次调用是最后一次):File“/Users/bildlich/Development/textfiles to mongodb/textfiles to mongodb.py”,第173行,在assumedentences.extend(filetocentencelist(textFilesDirectory+filename))File“/Users/bildlich/Development/textfiles to mongodb.py”,第147行,在filetocentencelist numberroperties=assumedentence['sence']中。计数(quotationMark['start'])UnicodeDecodeError:'ascii'编解码器无法解码字节0