设计注意事项
- 我只考虑了常规的
"double-quotes" 和'single-quotes'。可能还有其他引号(见this question)
- LaTeX 结束引号也是单引号 - 我们不想捕获 LaTeX 双引号(例如“LaTeX 双引号”)并将其误认为是单引号(几乎没有)李>
- 单词缩写和所有权
's 包含单引号(例如don't、John's)。它们的特点是字母字符围绕在引号的两侧
- 常规名词(复数所有权)在单词后有单引号(例如
the actresses' roles)
解决方案
import re
def texify_single_quote(in_string):
in_string = ' ' + in_string #Hack (see explanations)
return re.sub(r"(?<=\s)'(?!')(.*?)'", r"`\1'", in_string)[1:]
def texify_double_quote(in_string):
return re.sub(r'"(.*?)"', r"``\1''", in_string)
测试
with open("test.txt", 'r') as fd_in, open("output.txt", 'w') as fd_out:
for line in fd_in.readlines():
#Test for commutativity
assert texify_single_quote(texify_double_quote(in_string)) == texify_double_quote(texify_single_quote(in_string))
line = texify_single_quote(line)
line = texify_double_quote(line)
fd_out.write(line)
输入文件(test.txt):
# 'single', 'single', "double"
# 'single', "double", 'single'
# "double", 'single', 'single'
# "double", "double", 'single'
# "double", 'single', "double"
# I'm a 'single' person
# I'm a "double" person?
# Ownership for plural words; the peoples' 'rights'
# John's dog barked 'Woof!', and Fred's parents' 'loving' cat ran away.
# "A double-quoted phrase, with a 'single' quote inside"
# 'A single-quoted phrase with a "double quote" inside, with contracted words such as "don't"'
# 'A single-quoted phrase with a regular noun such as actresses' roles'
输出(output.txt):
# `single', `single', ``double''
# `single', ``double'', `single'
# ``double'', `single', `single'
# ``double'', ``double'', `single'
# ``double'', `single', ``double''
# I'm a `single' person
# I'm a ``double'' person?
# Ownership for plural words; the peoples' `rights'
# John's dog barked `Woof!', and Fred's parents' `loving' cat ran away.
# ``A double-quoted phrase, with a `single' quote inside''
# `A single-quoted phrase with a ``double quote'' inside, with contracted words such as ``don't'''
# `A single-quoted phrase with a regular noun such as actresses' roles'
(注意 cmets 被预先添加以停止对帖子输出进行格式化!)
说明
我们将分解这个正则表达式模式,(?<=\s)'(?!')(.*?)':
-
总结:
(?<=\s)'(?!') 处理开头的单引号,而(.*?) 处理引号中的内容。
-
(?<=\s)' 是 positive look-behind 并且只匹配前面有空格 (\s) 的单引号。这对于防止匹配缩略词(例如 can't)非常重要(注意事项 3、4)。
-
'(?!') 是 negative look-ahead,仅匹配 not 后跟另一个单引号的单引号(注意事项 2)。
- 如this answer 中所述,
(.*?) 模式捕获引号之间的内容,而\1 包含捕获内容。
-
"Hack"
in_string = ' ' + in_string 之所以存在,是因为正向后视 不 捕获从行首开始的单引号,因此为所有行(然后在返回时用切片删除它,return re.sub(...)[1:])解决了这个问题!