我正在尝试编写一个正则表达式来标准化名称。
用例:
J. J. Abrams -> JJ Abrams
J J Abrams -> JJ Abrams
J.J Abrams -> JJ Abrams
J.J. Abrams -> JJ Abrams
J J Abrams -> JJ Abrams (multiple spaces)
首字母可以出现在名称的末尾或中间。通常,首字母可以有空格或'。'或者在它之前或之后的单词边界。
所以我想出了以下内容:
p = re.compile(r'((\b|\s+|\.)[a-z](\.|\s+|\b))', re.I)
当我尝试匹配并打印结果时,它看起来不对:
p.subn(lambda g: g.groups()[0].strip().strip('.'), "J J Abrams")
('JJAbrams', 2)
如何在非初始部分之前(或之后)保留空间?
修改 此外,我应该说清楚,名称中不能只有2个首字母。以上只是一个随机用例。感谢
答案 0 :(得分:3)
对于给出的案例,替换
(?<=\b[A-Z]\b)[. ]+(?=[A-Z]\b)|\.|(\s)\s+
与
$1
应该这样做。
使用交替,在首字母,点之间或多于一个空格之间匹配空格和点。后者抓住了第一个空间。
用$1
替换它会从前两个替换中删除匹配,在第三种情况下(几个空格)用一个替换它们(第一个被捕获)。
答案 1 :(得分:1)
我认为你可以通过使用正则表达式分两步完成:
第1步:
正则表达式:
+|\. *
和替换(单个空格)
第2步:
正则表达式:
\b([a-z]) ([a-z])\b
替换:\1\2
通过组合你拥有的一切:
输入文件:
$ cat names
J. J. Abrams
J J Abrams
J.J Abrams
J.J. Abrams
J J Abrams
J Abrams J.
Abrams J. J.
Abrams J J
python代码:
$ cat names_norm.py
import re
import sys
with open("names") as file:
for line in file:
line = re.sub(r" +|\. *", " ", line)
line = re.sub(r"\b([a-zA-Z]) ([a-zA-Z])\b", "\g<1>\g<2>", line)
sys.stdout.write(line)
sys.stdout.flush()
<强>输出:强>
$ python names_norm.py
JJ Abrams
JJ Abrams
JJ Abrams
JJ Abrams
JJ Abrams
J Abrams J
Abrams JJ
Abrams JJ
答案 2 :(得分:0)
使用:
re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
<强>代码强>:
>>> s = 'J. J. Abrams'
>>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
JJ Abrams
>>> s = 'J J Abrams'
>>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
JJ Abrams
>>> s = 'J.J Abrams'
>>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
JJ Abrams
>>> s = 'J.J. Abrams'
>>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
JJ Abrams
>>> s = 'J J Abrams'
>>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
JJ Abrams
答案 3 :(得分:0)
您可以尝试查找所有连续字母并使用以下格式打印:
is_array
结果:
import re
if __name__=='__main__':
names = ["J. J. Abrams", "J J Abrams", "J.J Abrams", "J.J. Abrams", "J J Abrams", "J J J Abrams"]
for name in names:
res = re.findall("([a-z]+)", name, re.I) #Find all continuous alphabets
res.insert(len(res)-1, " "). #Insert <space> at second last position
print("res : %s" % ("".join(map(str, res)))) #Join and display list which is formatted
答案 4 :(得分:0)
因为您只想过滤掉“。”我建议只使用标准的字符串方法。
为了您的愉快,我把它写成一个完全不可读的单行。
names = ['J. R. R. Tolkien', # "." and " "
'Abrams J J', # " "
'J.J Abrams', # "." inbetween
'J.R.R. Tolkien', # "."
'J R.R Tolkien'] # mixed
for name in names :
name = "".join([(" {} ".format(elem)) if len(elem)>1 else elem for elem in name.replace('.', ' ').split()]).strip()
print name
这导致了这个输出。
JRR Tolkien
Abrams JJ
JJ Abrams
JRR Tolkien
JRR Tolkien
修改强>
@ClasG的解决方案也可能不可读。但我的解决方案甚至需要两倍的时间进行计算。
Elapsed time, mean value: 6.92432632016e-06
Elapsed time, mean value: 1.5598555044e-05