在字符串中找到重复的单词并打印它们

2024-10-04 05:25:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要一些帮助打印文本文件中重复的姓氏(小写和大写应该相同) 程序不打印带数字的单词(例如,如果数字出现在姓或名中,则忽略整个姓名)

例如: 我的文本文件是:

Assaf Spanier, Assaf Din, Yo9ssi Levi, Yoram bibe9rman, David levi, Bibi Netanyahu, Amnon Levi, Ehud sPanier, Barak Spa7nier, Sara Neta4nyahu

输出应为:

^{pr2}$

import re def delete_numbers(line): words = re.sub(r'\w*\d\w*', '', line).strip() for t in re.split(r',', words): if len(t.split()) == 1: words = re.sub(t, '',words) words = re.sub(',,', '', words) return words fname = input("Enter file name: ") file = open(fname,"r") for line in file.readlines(): words = delete_numbers(line) first_name = re.findall(r"([a-zA-Z]+)\s",words) for i in first_name: print(i) print("***") a = "" for t in re.split(r',', words): a+= (", ".join(t.split()[1:])) + " "


Tags: nameinreforline数字deletefname
2条回答

好吧,既然你坚持用正则表达式来做,你应该努力在一个调用中完成,这样你就不会受到上下文切换的惩罚。最好的方法是编写一个模式来捕获不包含数字的所有名/姓,用逗号分隔,让正则表达式引擎捕获所有这些名字,然后迭代匹配项,最后将它们映射到字典,以便可以将它们拆分为姓氏=>;名字映射:

import collections
import re

text = "Assaf Spanier, Assaf Din, Yo9ssi Levi, Yoram bibe9rman, David levi, " \
       "Bibi Netanyahu, Amnon Levi, Ehud sPanier, Barak Spa7nier, Sara Neta4nyahu"

full_name = re.compile(r"(?:^|\s|,)([^\d\s]+)\s+([^\d\s]+)(?=>$|,)")  # compile the pattern

matches = collections.OrderedDict()  # store for the last=>first name map preserving order
for match in full_name.finditer(text):
    first_name = match.group(1)
    print(first_name)  # print the first name to match your desired output
    last_name = match.group(2).title()  # capitalize the last name for case-insensitivity
    if last_name in matches:  # repeated last name
        matches[last_name].append(first_name)  # add the first name to the map
    else:  # encountering this last name for the first time
        matches[last_name] = [first_name]  # initialize the map for this last name
print("========")  # print the separator...
# finally, print all the repeated last names to match your format
for k, v in matches.items():
    if len(v) > 1:  # print only those with more than one first name attached
        print(k)

这会给你:

^{pr2}$

另外,在matches中有完整的姓氏=>;名字匹配。在

说到图案,让我们一块一块地分解:

(?:^|\s|,) - match the beginning of the string, whitespace or a comma (non-capturing)
  ([^\d\,]+) - followed by any number of characters that are not not digits or whitespace
               (capturing)
    \s+  - followed by one or more whitespace characters (non-capturing)
      ([^\d\s]+) - followed by the same pattern as for the first name (capturing)
         (?=>$|,) - followed by a comma or end of the string  (look-ahead, non-capturing)

当我们迭代匹配项时,match对象中会引用这两个捕获的组(名字和姓氏)。别紧张。在

好的,首先让我们从一个侧面开始-用惯用的方式打开文件。使用with语句,它保证文件将被关闭。对于小脚本来说,这并不是什么大问题,但是如果您开始编写寿命更长的程序,由于错误关闭的文件而导致的内存泄漏可能会再次困扰您。因为您的文件将所有内容都放在一行:

with open(fname) as f:
    data = f.read()

文件现在已关闭。这也鼓励您立即处理您的文件,而不是让它打开不必要地消耗资源。另外,假设你有多条线。不要使用for line in f.readlines(),请使用以下构造:

^{pr2}$

因为实际上不需要保存整个文件,只需要检查每一行,所以不要使用readlines()。如果您想保留一个行列表,比如lines = f.readlines(),只使用readlines()。在

好的,最后,数据如下所示:

>>> print(data)
Assaf Spanier, Assaf Din, Yo9ssi Levi, Yoram bibe9rman, David levi, Bibi Netanyahu, Amnon Levi, Ehud sPanier, Barak Spa7nier, Sara Neta4nyahu

好的,如果您想在这里使用regex,我建议使用以下方法:

>>> names_regex = re.compile(r"^(\D+)\s(\D+)$")

这里的模式^(\D+)\s(\D+)$使用非数字组,\D(与\d相反,数字组)和空白组\s。此外,它还使用^和{},分别将模式锚定到文本的开头和结尾。另外,括号中创建了捕获组,我们将利用它。试着把这个复制粘贴到http://regexr.com/中,如果你还是不明白,就试试看。一个重要的注意事项是使用原始字符串,即r"this is a raw string"与普通字符串"this is a normal string"(注意r)。这是因为Python字符串使用与regex模式相同的转义字符。这有助于保持你的理智。好的,最后,我建议使用分组习惯用法,加上dict

>>> grouper = {}

现在,我们的循环:

>>> for fullname in data.split(','):
...     match = names_regex.search(fullname.strip())
...     if match:
...         first, last = match.group(1), match.group(2)
...         grouper.setdefault(last.title(), []).append(first.title())
...

注意,我使用.title方法将我们所有的名字规范化为“Titlecase”。dict.setdefault接受一个键作为它的第一个参数,如果这个键不存在,它将第二个参数设置为值,并返回它。所以,我要检查姓氏(在title case中)是否存在于grouperdict中,如果不存在,则将其设置为空列表,[],然后{}将其设置为任何内容!在

为了清晰起见,现在印刷精美:

>>> from pprint import pprint
>>> pprint(grouper)
{'Din': ['Assaf'],
 'Levi': ['David', 'Amnon'],
 'Netanyahu': ['Bibi'],
 'Spanier': ['Assaf', 'Ehud']}

这是一个非常有用的数据结构。例如,我们可以获取具有多个名字的所有姓氏:

>>> for last, firsts in grouper.items():
...     if len(firsts) > 1:
...         print(last)
...
Spanier
Levi

所以,把它们放在一起:

>>> grouper = {}
>>> names_regex = re.compile(r"^(\D+)\s(\D+)$")
>>> for fullname in data.split(','):
...     match = names_regex.search(fullname.strip())
...     if match:
...         first, last = match.group(1), match.group(2)
...         first, last = first.title(), last.title()
...         print(first)
...         grouper.setdefault(last, []).append(first)
...
Assaf
Assaf
David
Bibi
Amnon
Ehud
>>> for last, firsts in grouper.items():
...     if len(firsts) > 1:
...         print(last)
...
Spanier
Levi

注意,我假设顺序无关紧要,所以我使用了普通的dict。我的输出恰好是按正确的顺序排列的,因为在python3.6上,dict是按顺序排列的!但不要依赖于此,因为它是实现细节,而不是保证。如果要保证订单,请使用collections.OrderedDict。在

相关问题 更多 >