簡體   English   中英

Python:將字符串中的“啞引號”替換為“卷曲引號”

[英]Python: Replace “dumb quotation marks” with “curly ones” in a string

我有一個這樣的字符串:

“但是那位先生,”看着達西,“似乎認為這個國家什么都不是。”

我想要這個輸出:

“但是那位先生,”看着達西,“似乎認為這個國家什么都不是。”

同樣,愚蠢的單引號應該轉換為它們的卷曲等價物。 如果您有興趣,請在此處閱讀有關排版規則的信息。

我的猜測是之前已經解決了這個問題,但我找不到一個庫或腳本來做到這一點。 SmartyPants (Perl) 是執行此操作的所有庫之母,並且有一個python 端口 但它的輸出是 HTML 實體: “But that gentleman,” 我只想要一個帶卷曲引號的普通字符串。 有什么想法嗎?

更新:

我按照 Padraig Cunningham 的建議解決了這個問題:

  1. 使用 smartypants 進行排版更正
  2. 使用HTMLParser().unescape將 HTML 實體轉換回 Unicode

如果您的輸入文本包含您不希望轉換的 HTML 實體,則此方法可能會出現問題,但在我的情況下,這沒問題。

更新結束

輸入是否可信?

到目前為止,輸入只能被信任。 該字符串可以包含一個非封閉的雙引號: "But be that gentleman, looking at Dary 。它也可以包含一個非封閉的單引號: 'But be that gentleman, looking at Dary 。最后,它可以包含一個單-引用這是一個撇號: Don't go there.

我已經實現了一個試圖正確關閉這些丟失的引號的算法,所以這不是問題的一部分。 為了完整起見,這里是關閉丟失引號的代碼:

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']

您可以使用HTMLParser來取消轉義從 smartypants 返回的 html 實體:

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"或將字符串解碼為 un​​icode:

 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 中替換字符的選項

你 = 256

輸出 Unicode 字符而不是數字字符引用,例如,從“到左雙引號 (“) (U+201C)。

瀏覽文檔,看起來你被困在 smartypants 之上的.replace

smartypants(r'"smarty" \"pants\"').replace('&#x201C;', '“').replace('&#x201D;', '”')

但是,如果您為魔術字符串設置別名,可能會讀得更好:

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.’

我在這里通過假設它們位於行的開頭/結尾或周圍有空格來分離單引號。

對於最簡單的用例,不需要正則表達式:

quote_chars_counts = {
    '"': 0,
    "'": 0,
    "`": 0
}


def to_smart_quotes(s):
    output = []

    for c in s:
        if c in quote_chars_counts.keys():
            replacement = (quote_chars_counts[c] % 2 == 0) and '“' or '”'
            quote_chars_counts[c] = quote_chars_counts[c] + 1
            new_ch = replacement
        else:
            new_ch = c
        output.append(new_ch)

    return ''.join(output)

如果需要,修改以從替換映射中提取替換而不是使用文字是微不足道的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM