【问题标题】:Python Replace Single Quotes Except ApostrophesPython替换单引号,撇号除外
【发布时间】:2018-11-19 12:33:46
【问题描述】:

我正在对单词列表执行以下操作。我从 Project Gutenberg 文本文件中读取行,用空格分隔每一行,执行一般的标点符号替换,然后将每个单词和标点符号标签打印在其自己的行上以供以后进一步处理。我不确定如何用标签替换每个单引号或将所有撇号除外。我目前的方法是使用编译的正则表达式:

apo = re.compile("[A-Za-z]'[A-Za-z]")

并执行以下操作:

if "'" in word and !apo.search(word):
    word = word.replace("'","\n<singlequote>")

但这忽略了在带有撇号的单词周围使用单引号的情况。它也没有向我表明单引号是紧靠单词的开头还是单词的结尾。

示例输入:

don't
'George
ma'am
end.'
didn't.'
'Won't

示例输出(处理并打印到文件后):

don't
<opensingle>
George
ma'am
end
<period>
<closesingle>
didn't
<period>
<closesingle>
<opensingle>
Won't

关于这个任务我还有一个问题:既然区分&lt;opensingle&gt;&lt;closesingle&gt; 似乎相当困难,那么执行类似的替换是否更明智

word = word.replace('.','\n<period>')
word = word.replace(',','\n<comma>')

执行替换操作之后?

【问题讨论】:

  • 你如何定义一个词?
  • 它只是一个数组中的字符串,由 words = line.split() 产生。当我打印到文件时,我只是在空格上分割一行并使用 \n 字符将标点符号剥离到新行上的标签中。但我不想去掉撇号,因为我认为从字面意义上来说,缩略词是可以适当定义的“词”。
  • 另一种情况(我忘了提)是连字符:我不想分解连字符。

标签: python regex substitution single-quotes


【解决方案1】:

我建议在这里聪明地工作:改用nltk's 或其他 NLP 工具包。

Tokenize words 像这样:

import nltk
sentence = """At eight o'clock on Thursday morning
Arthur didn't feel very good."""
tokens = nltk.word_tokenize(sentence)

您可能不喜欢这样的缩略词不分开的事实。实际上,这是预期的行为。见Issue 401

不过,TweetTokenizer 可以提供帮助:

from nltk.tokenize import tknzr = TweetTokenizer()
tknzr.tokenize("The code didn't work!")

如果涉及更多,RegexpTokenizer 可能会有所帮助:

from nltk.tokenize import RegexpTokenizer
s = "Good muffins cost $3.88\nin New York.  Please don't buy me\njust one of them."
tokenizer = RegexpTokenizer('\w+|\$[\d\.]+|\S+')
tokenizer.tokenize(s)

那么正确注释标记化的单词应该会容易得多。

更多参考资料:

【讨论】:

  • 我很欣赏引入了一个新工具(我保证我会使用它,即使是在我开始对比约瑟夫康拉德的《黑暗之心》更复杂的书籍执行此标记时),但对于目前的情况我觉得 NLP 是矫枉过正。当然,我曾尝试使用 sed 执行此任务并放弃了,转而使用 Python,所以也许我很快就会结束 NLP。
  • @malan 欢迎您。你肯定会的;可以说,如果你在没有 NLP 工具包的情况下处理文献,那你就做错了。
  • 我现在对部署这个工具包很感兴趣:它能否识别开引号和省略单引号之间的区别(例如“Let's get 'em”中的那个)?
【解决方案2】:

你真正需要正确替换开始和结束'正则表达式。 要匹配它们,您应该使用:

  • ^' 用于启动 ' (opensingle),
  • '$ 结束 ' (closesingle)。

很遗憾,replace 方法不支持正则表达式, 所以你应该改用re.sub

下面有一个示例程序,打印您想要的输出 (在 Python 3 中):

import re
str = "don't 'George ma'am end.' didn't.' 'Won't"
words = str.split(" ")
for word in words:
    word = re.sub(r"^'", '<opensingle>\n', word)
    word = re.sub(r"'$", '\n<closesingle>', word)
    word = word.replace('.', '\n<period>')
    word = word.replace(',', '\n<comma>')
    print(word)

【讨论】:

    【解决方案3】:

    我认为这可以从前瞻或后视引用中受益。 python 参考是https://docs.python.org/3/library/re.html,我经常参考的一个通用正则表达式站点是https://www.regular-expressions.info/lookaround.html

    您的数据:

    words = ["don't",
             "'George",
             "ma'am",
             "end.'",
             "didn't.'",
             "'Won't",]
    

    现在我将使用正则表达式及其替换定义一个元组。

    In [230]: apo = (
        (re.compile("(?<=[A-Za-z])'(?=[A-Za-z])"), "<apostrophe>",),
        (re.compile("(?<![A-Za-z])'(?=[A-Za-z])"), "<opensingle>",),
        (re.compile("(?<=[.A-Za-z])'(?![A-Za-z])"), "<closesingle>", ),
        (re.compile("(?<=[A-Za-z])\\.(?![A-Za-z])"), "<period>",),
    )
         ...:      ...:      ...:      ...:      ...:      ...: 
    In [231]: words = ["don't",
             "'George",
             "ma'am",
             "end.'",
             "didn't.'",
             "'Won't",]
         ...:      ...:      ...:      ...:      ...:      ...: 
    In [232]: reduce(lambda w2,x: [ x[0].sub(x[1], w) for w in w2], apo, words)
    Out[232]: 
    ['don<apostrophe>t',
     '<opensingle>George',
     'ma<apostrophe>am',
     'end<period><closesingle>',
     'didn<apostrophe>t<period><closesingle>',
     '<opensingle>Won<apostrophe>t']
    

    下面是正则表达式的情况:

    1. (?&lt;=[A-Za-z]) 是一个lookbehind,意思是只匹配(但不消耗)如果前面的字符是一个字母。
    2. 如果后面的字符是字母,(?=[A-Za-z])lookahead(仍然没有消耗)。
    3. (?&lt;![A-Za-z]) 是一个否定的lookbehind,意思是如果它前面有一个字母,那么它将不匹配。
    4. (?![A-Za-z]) 是一个否定的前瞻

    请注意,我在&lt;closesingle&gt; 中添加了. 检查,apo 中的顺序很重要,因为您可能会将. 替换为&lt;period&gt; ...

    这是对单个单词进行操作,但也适用于句子。

    In [233]: onelong = """
    don't
    'George
    ma'am
    end.'
    didn't.'
    'Won't
    """
         ...:      ...:      ...:      ...:      ...:      ...:      ...: 
    In [235]: print(
        reduce(lambda sentence,x: x[0].sub(x[1], sentence), apo, onelong)
    )
    
         ...:      ...: 
    don<apostrophe>t
    <opensingle>George
    ma<apostrophe>am
    end<period><closesingle>
    didn<apostrophe>t<period><closesingle>
    <opensingle>Won<apostrophe>t
    

    reduce 的使用是为了便于在单词/字符串上应用正则表达式的 .sub,然后将输出保留给下一个正则表达式的 .sub 等)

    【讨论】:

      猜你喜欢
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多