Python 替换单引号(撇号除外)
Python Replace Single Quotes Except Apostrophes
我正在对单词列表执行以下操作。我从 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
关于这个任务我还有一个问题:既然区分 <opensingle>
和 <closesingle>
似乎相当困难,那么执行像
这样的替换会更明智吗?
word = word.replace('.','\n<period>')
word = word.replace(',','\n<comma>')
在执行替换操作后?
我建议在这里聪明地工作:改用 nltk 或其他 NLP 工具包。
Tokenize words 像这样:
import nltk
sentence = """At eight o'clock on Thursday morning
Arthur didn't feel very good."""
tokens = nltk.word_tokenize(sentence)
您可能不喜欢像 don't 这样的缩写是分开的。实际上,这是预期的行为。参见 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 .88\nin New York. Please don't buy me\njust one of them."
tokenizer = RegexpTokenizer('\w+|$[\d\.]+|\S+')
tokenizer.tokenize(s)
那么正确标注分词词应该就容易多了。
进一步参考:
正确替换开始和结束真正需要的东西'
是 regex。
要匹配它们,您应该使用:
^'
用于启动 '
(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)
我认为这可以从前瞻或后视引用中获益。 python 引用是 https://docs.python.org/3/library/re.html, and one generic regex site I often reference is 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']
以下是正则表达式的情况:
(?<=[A-Za-z])
是一个 lookbehind,意思是仅匹配(但 不消耗 )如果前面的字符是字母.
(?=[A-Za-z])
是 lookahead(仍然没有消耗)如果后面的字符是字母。
(?<![A-Za-z])
是一个负向回顾,意思是如果它前面有一个字母,那么它就不会匹配。
(?![A-Za-z])
是一个 负前瞻 .
请注意,我在 <closesingle>
中添加了一个 .
检查,并且 apo
中的顺序很重要,因为您可能会将 .
替换为 <period>
...
这是对单个词的操作,但也适用于句子。
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
是为了方便在 words/strings 上应用正则表达式的 .sub
,然后为下一个正则表达式的 .sub
等保留该输出。
我正在对单词列表执行以下操作。我从 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
关于这个任务我还有一个问题:既然区分 <opensingle>
和 <closesingle>
似乎相当困难,那么执行像
word = word.replace('.','\n<period>')
word = word.replace(',','\n<comma>')
在执行替换操作后?
我建议在这里聪明地工作:改用 nltk 或其他 NLP 工具包。
Tokenize words 像这样:
import nltk
sentence = """At eight o'clock on Thursday morning
Arthur didn't feel very good."""
tokens = nltk.word_tokenize(sentence)
您可能不喜欢像 don't 这样的缩写是分开的。实际上,这是预期的行为。参见 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 .88\nin New York. Please don't buy me\njust one of them."
tokenizer = RegexpTokenizer('\w+|$[\d\.]+|\S+')
tokenizer.tokenize(s)
那么正确标注分词词应该就容易多了。
进一步参考:
正确替换开始和结束真正需要的东西'
是 regex。
要匹配它们,您应该使用:
^'
用于启动'
(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)
我认为这可以从前瞻或后视引用中获益。 python 引用是 https://docs.python.org/3/library/re.html, and one generic regex site I often reference is 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']
以下是正则表达式的情况:
(?<=[A-Za-z])
是一个 lookbehind,意思是仅匹配(但 不消耗 )如果前面的字符是字母.(?=[A-Za-z])
是 lookahead(仍然没有消耗)如果后面的字符是字母。(?<![A-Za-z])
是一个负向回顾,意思是如果它前面有一个字母,那么它就不会匹配。(?![A-Za-z])
是一个 负前瞻 .
请注意,我在 <closesingle>
中添加了一个 .
检查,并且 apo
中的顺序很重要,因为您可能会将 .
替换为 <period>
...
这是对单个词的操作,但也适用于句子。
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
是为了方便在 words/strings 上应用正则表达式的 .sub
,然后为下一个正则表达式的 .sub
等保留该输出。