如何使用Python正则表达式提取特定字符串

2024-09-29 23:28:20 发布

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

我一直在努力解决非常具有挑战性的问题。
比如说,

str1 = '95% for Pikachu, 92% for Sandshrew'
str2 = '70% for Paras & 100% Arcanine'
str3 = '99% Diglett, 40% Dugtrio'
str4 = '10% Squirtle, 100% for Alakazam'
str5 = '30% Metopod & 99% Dewgong'

字符串以%整数开头,可能有for或没有,然后是口袋妖怪的名称。可能有comma(,)&符号,然后是新的%整数。最后还有一个口袋妖怪的名字。(都以大写字母开头)
我想提取两个口袋妖怪,例如result

['Pikachu', 'Sandshrew']
['Paras', 'Arcanine']
['Diglett', 'Dugtrio']
['Squirtle', 'Alakazam']
['Metopod', 'Dewgong']

我可以使用in语法创建所有pokemen的列表,但这不是最好的方法(以防他们添加更多pokemon)。是否可以使用正则表达式进行提取?
提前谢谢
编辑
根据要求,我正在添加我的代码

str_list = [str1, str2, str3, str4, str5]

for x in str_list:
    temp_list = []
    if 'for' in x:
        temp = x.split('% for', 1)[1].strip()
        temp_list.append(temp)
    else:
        temp = x.split(" ", 1)[1]
        temp_list.append(temp)
print(temp_list)

我知道这不是regex express。我尝试的表达式是,\d+to 提取整数以开始。。。但是不知道如何开始。
EDIT2
@b_c有很好的边缘情况,所以,我在这里添加它

edge_str = '100% for Pikachu, 29% Pika Pika Pikachu'

结果

['Pikachu', 'Pika Pika Pikachu']

Tags: infor整数temppikaliststr口袋妖怪
3条回答

希望我没有过度设计这个,但我想涵盖稍微复杂一点的命名口袋妖怪的边缘案例,比如“Mime先生”、“Farfetch'd”和/或“Nidoran”♂" (只看前151页)

我使用的模式是(?:(?:\d+%(?: |for)+([A-Z](?:[\w\.♀♂']|(?: (?=[A-Z])))+))+)[, &]*,它看起来在我的测试中起作用(下面是regex101 link的分解图)

对于一般性总结,我希望:

  • 1+位数后接a%
  • 一个空格或单词“for”至少一次
  • (开始捕捉)起始大写字母
  • 至少一个(结束捕获组):
    • 单词字符、句号、男性/女性符号或撇号
      • 注意:如果您想捕获其他“怪异”的口袋妖怪字符,如数字、冒号等,请将它们添加到该部分(即[\w\.♀♂']位)
    • 或空格,但如果后跟大写字母,则仅
  • 逗号、空格或符号,任意次数

除非对其进行更改,否则Python的内置re模块不支持重复捕获组(我认为我这样做是正确的),所以我只是使用re.findall并将它们组织成对(我用复杂的名称替换了输入中的几个名称):

import re

str1 = '95% for Pikachu, 92% for Mr. Mime'
str2 = '70% for Paras & 100% Arcanine'
str3 = '99% Diglett, 40% Dugtrio'
str4 = "10% Squirtle, 100% for Farfetch'd"
str5 = '30% Metopod & 99% Nidoran♂'

pattern = r"(?:(?:\d+%(?: |for)+([A-Z](?:[\w\.♀♂']|(?: (?=[A-Z])))+))+)[, &]*"

# Find matches in each string, then unpack each list of
# matches into a flat list
all_matches = [match
               for s in [str1, str2, str3, str4, str5]
               for match in re.findall(pattern, s)]

# Pair up the matches
pairs = zip(all_matches[::2], all_matches[1::2])

for pair in pairs:
    print(pair)

然后打印出:

('Pikachu', 'Mr. Mime')
('Paras', 'Arcanine')
('Diglett', 'Dugtrio')
('Squirtle', "Farfetch'd")
('Metopod', 'Nidoran♂')

另外,正如前面提到的,pokemon名称中确实有一些拼写错误,但regex不是解决这个问题的正确方法(很遗憾:)

因为字符串中似乎没有其他大写字母,所以可以简单地使用[A-Z]\w+作为正则表达式。 见regex101

代码:

import re

str1 = '95% for Pikachu, 92% for Sandsherew'
str2 = '70% for Paras & 100% Arcanine'
str3 = '99% Diglett, 40% Dugtrio'
str4 = '10% Squirtle, 100% for Alakazam'
str5 = '30% Metopod & 99% Dewgong'

str_list = [str1, str2, str3, str4, str5]
regex = re.compile('[A-Z]\w+')
pokemon_list = []
for x in str_list:
    pokemon_list.append(re.findall(regex, x))
print(pokemon_list)

输出:

[['Pikachu', 'Sandsherew'], ['Paras', 'Arcanine'], ['Diglett', 'Dugtrio'], ['Squirtle', 'Alakazam'], ['Metopod', 'Dewgong']]

如果您不想使用正则表达式,也不想依赖于大写,那么可以使用另一种方法

def pokeFinder(strng):
    wordList = strng.split()
    pokeList = []
    for word in wordList:
        if not set('[~!@#$%^&*()_+{}":;\']+$').intersection(word) and 'for' not in word:
            pokeList.append(word.replace(',', ''))
    return pokeList

这不会添加带有特殊字符的单词。它也不会添加for的单词。然后从找到的单词中删除逗号

str2的打印返回['Diglett', 'Dugtrio']


编辑 鉴于有两个单词和特殊字符的口袋妖怪,我制作了上面代码的这个稍微复杂的版本

def pokeFinder(strng):
    wordList = strng.split()
    pokeList = []
    prevWasWord = False
    for word in wordList:
        if not set('%&').intersection(word) and 'for' not in word:
            clnWord = word.replace(',', '')
            if prevWasWord is True: # 2 poke in a row means same poke
                pokeList[-1] = pokeList[-1] + ' ' + clnWord
            else:
                pokeList.append(clnWord)
                prevWasWord = True
        else:
            prevWasWord = False
    return pokeList

如果没有“三个字”的口袋妖怪,并且规则操作集保持不变,那么这应该总是有效的。连续两次戳匹配将添加到上一个口袋妖怪

所以打印一串'30% for Mr. Mime & 20% for Type: Null'会得到 ['Mr. Mime', 'Type: Null']

相关问题 更多 >

    热门问题