【问题标题】:Replace elements in list with substring contained in elements用元素中包含的子字符串替换列表中的元素
【发布时间】:2021-11-26 18:05:28
【问题描述】:

鉴于这份名单

names=['Anna, Mrs. James (Nadia Elf)', 'Martin, Mr. Michael ', 'Barese, Mr. Alfred', 'Amalfi, Mrs. Abby (J E V)'
      ,'Manuel, Dr. Louis']

我正在尝试将每个名称替换为其标题。

例如,名字是“安娜,詹姆斯夫人 (Nadia Elf)” 我想用“夫人”替换它。

为了确保以下代码按我想要的方式工作,并且每个名称都被其标题替换,我必须重复这些行

titles = []
for i in names:
    new_string = i.replace("Anna, Mrs. James (Nadia Elf)", "Mrs")
    titles.append(new_string)
print(titles)

列表中的每一项。 我应该如何编写一个不超过几行的代码来处理这个问题?

【问题讨论】:

  • 标题是否总是作为每个名称字符串中逗号后的第一个元素给出?如果是这样,您可以拆分每个名称,(或使用更优雅的正则表达式)选择此元素并执行替换。
  • 提示:new_string = i.replace("Anna, Mrs. James (Nadia Elf)", "Mrs") 可以是 new_string = "Mrs"。现在你只需要根据i知道在作业的右侧放什么。
  • @albert 不一定
  • 提示 2:要检查字符串 title 是否包含在另一个字符串 name 中,请使用 title in name
  • 避免脆弱性的最佳方法是对输入使用相同的规则,并强制执行您以后可以明确解析的格式。但我不确定这是否有资格作为答案,所以请留下评论。

标签: python list replace substring


【解决方案1】:

假设一个人的标题总是位于逗号之后的第一个元素,您可以应用一系列 .split() ,如我的第一种方法所示。但是,由于情况可能并非如此,您可以使用正则表达式来查找以点结尾并在逗号后面的部分中被空格包围的任何多字符字符串,如我的第二种方法所示:

import re

names = [
    'Anna, Mrs. James (Nadia Elf)',
    'Martin, Mr. Michael',
    'Barese, Mr. Alfred',
    'Amalfi, Mrs. Abby (J E V)',
    'Manuel, Dr. Louis'
]

regex = r'.+\,\s(.+\.)\s'
preg = re.compile(regex)


def split_name(s):
    # assuming that the title is the first element after the comma
    return s.split(',')[-1].strip().split(' ', 1)[0]


def regex_name(s):
    # a more flexible approach, assuming the title is always ending with a dot and there are not other dots in the name
    m = preg.match(s)
    if m:
        ret, = m.groups(0)
        return ret


# use first approach based on split
titles = [split_name(name) for name in names]
print(titles)


# use second approach based on regex
titles = [regex_name(name) for name in names]
print(titles)

打印输出:

['Mrs.', 'Mr.', 'Mr.', 'Mrs.', 'Dr.']
['Mrs.', 'Mr.', 'Mr.', 'Mrs.', 'Dr.']

【讨论】:

    【解决方案2】:

    这是一种处理任何标题的正则表达式方法。您唯一需要注意的是,没有其他单词紧随其后;例如,就像在一个句子中。

    为了解决这个问题,我想您可以将正则表达式限制为仅匹配句点前包含 2-3 个字母的单词。

    import re
    
    names = ['Anna, Mrs. James (Nadia Elf)',
             'Martin, Mr. Michael ',
             'Barese, Mr. Alfred',
             'Amalfi, Mrs. Abby (J E V)',
             'Manuel, Dr. Louis']
    
    titles = [re.sub(r'.*\b(\w+\.)(?:$|\s).*', r'\1', name) for name in names]
    
    print(titles)
    # ['Mrs.', 'Mr.', 'Mr.', 'Mrs.', 'Dr.']
    

    编辑:这是一个更严格的正则表达式,您也可以使用.*\b([A-Z]\w{1,2}\.)(?:$|\s).*

    这匹配一个大写字符,后跟 1-2 个字符,然后是句点。例如,它匹配像Mrs. 这样的标题,但不匹配mrs.

    这是一个测试链接:Link


    正如 cmets 中所提到的,对于某些输入,这可能会表现得有些出乎意料。例如,给定一个像"Joe Smith, Jr." 这样的字符串,它将确定标题为Jr.,这可能不是我们想要的。

    输入中还有一些其他边缘情况,可能值得考虑(目前上面的正则表达式不考虑):

    • 多个标题
    • 中间的首字母(我想上面的正则表达式的“更严格”变体已经涵盖了这一点,因此不应匹配像 L. 这样的首字母,只要它只有一个字母长)
    • Miss、Lord、Sir、Madam 等变体

    【讨论】:

    • 一个很好的方法,但输入似乎确实是脆弱的潜在来源。考虑一下“Joe Smith, Jr”这个名字。多头衔呢?中间名首字母?小姐,主,伊玛目? (我不建议立即解决所有问题,只是提及问题。)
    • @KennyOstrom 是的,这是一个很好的观点。我更新了上面的答案,提到了我同意它们可能是一个问题的边缘情况。
    【解决方案3】:

    如果您只有 'Mr' 和 'Mrs' 这两个选项,只需检查它们是否在字符串中。

    ['Mr' if 'Mr' in name else 'Mrs' for name in name]
    

    编辑:我注意到您还有其他头衔,例如“博士”,您应该首先创建一个 dict 或者甚至是您想要解决的所有头衔的 ENUM,然后按照上面的示例进行操作

    【讨论】:

    • 在此示例中,我有 3 个选项:先生、夫人和博士,但我想将此应用于选项至少为 5 个的场景
    • 我担心“Dr”在“Drummond”中,例如
    【解决方案4】:

    除了使用正则表达式。您可以使用列表理解

    names=['Anna, Mrs. James (Nadia Elf)', 'Martin, Mr. Michael ', 'Barese, Mr. Alfred', 'Amalfi, Mrs. Abby (J E V)', 'Manuel, Dr. Louis']
    titles = [(name.split(',')[1].split('.')[0]) for name in names]
    print(titles)
    

    打印输出

    [' Mrs', ' Mr', ' Mr', ' Mrs', ' Dr']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      • 2011-10-29
      • 2021-12-19
      • 2021-09-26
      • 2021-04-17
      • 2012-10-11
      • 2016-04-09
      相关资源
      最近更新 更多