<p>好的,首先让我们从一个侧面开始-用惯用的方式打开文件。使用<code>with</code>语句,它保证文件将被关闭。对于小脚本来说,这并不是什么大问题,但是如果您开始编写寿命更长的程序,由于错误关闭的文件而导致的内存泄漏可能会再次困扰您。因为您的文件将所有内容都放在一行:</p>
<pre><code>with open(fname) as f:
data = f.read()
</code></pre>
<p>文件现在已关闭。这也鼓励您立即处理您的文件,而不是让它打开不必要地消耗资源。另外,假设你有多条线。不要使用<code>for line in f.readlines()</code>,请使用以下构造:</p>
^{pr2}$
<p>因为实际上不需要保存整个文件,只需要检查每一行,所以不要使用<code>readlines()</code>。如果您想保留一个行列表,比如<code>lines = f.readlines()</code>,只使用<code>readlines()</code>。在</p>
<p>好的,最后,数据如下所示:</p>
<pre><code>>>> print(data)
Assaf Spanier, Assaf Din, Yo9ssi Levi, Yoram bibe9rman, David levi, Bibi Netanyahu, Amnon Levi, Ehud sPanier, Barak Spa7nier, Sara Neta4nyahu
</code></pre>
<p>好的,如果您想在这里使用regex,我建议使用以下方法:</p>
<pre><code>>>> names_regex = re.compile(r"^(\D+)\s(\D+)$")
</code></pre>
<p>这里的模式<code>^(\D+)\s(\D+)$</code>使用<em>非数字</em>组,<code>\D</code>(与<code>\d</code>相反,数字组)和空白组<code>\s</code>。此外,它还使用<em>锚</em>、<code>^</code>和{<cd11>},分别将模式锚定到文本的开头和结尾。另外,括号中创建了捕获组,我们将利用它。试着把这个复制粘贴到<a href="http://regexr.com/" rel="nofollow noreferrer">http://regexr.com/</a>中,如果你还是不明白,就试试看。一个重要的注意事项是使用原始字符串,即<code>r"this is a raw string"</code>与普通字符串<code>"this is a normal string"</code>(注意<code>r</code>)。这是因为Python字符串使用与regex模式相同的转义字符。这有助于保持你的理智。好的,最后,我建议使用分组习惯用法,加上<code>dict</code></p>
<pre><code>>>> grouper = {}
</code></pre>
<p>现在,我们的循环:</p>
<pre><code>>>> 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())
...
</code></pre>
<p>注意,我使用<code>.title</code>方法将我们所有的名字规范化为“Titlecase”。<code>dict.setdefault</code>接受一个键作为它的第一个参数,如果这个键不存在,它将第二个参数设置为值,并返回它。所以,我要检查姓氏(在title case中)是否存在于<code>grouper</code>dict中,如果不存在,则将其设置为空列表,<code>[]</code>,然后{<cd20>}将其设置为任何内容!在</p>
<p>为了清晰起见,现在印刷精美:</p>
<pre><code>>>> from pprint import pprint
>>> pprint(grouper)
{'Din': ['Assaf'],
'Levi': ['David', 'Amnon'],
'Netanyahu': ['Bibi'],
'Spanier': ['Assaf', 'Ehud']}
</code></pre>
<p>这是一个非常有用的数据结构。例如,我们可以获取具有多个名字的所有姓氏:</p>
<pre><code>>>> for last, firsts in grouper.items():
... if len(firsts) > 1:
... print(last)
...
Spanier
Levi
</code></pre>
<p>所以,把它们放在一起:</p>
<pre><code>>>> 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
</code></pre>
<p>注意,我假设顺序无关紧要,所以我使用了普通的<code>dict</code>。我的输出恰好是按正确的顺序排列的,因为在python3.6上,<code>dict</code>是按顺序排列的!但不要依赖于此,因为它是实现细节,而不是保证。如果要保证订单,请使用<code>collections.OrderedDict</code>。在</p>