正则表达式策略在一种情况下有效,但在另一种情况下无效

2024-04-26 02:49:15 发布

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

给出了python3.7.3和Pandas 0.25.0上的数据

import pandas as pd
test = {'data':['1/2 lorem ipsum','2/3 ipsum lorem 4/5','6/7 lorem ipsum',
'8.2/9 ipsum lorem 10.12/13']}
df = pd.DataFrame(test)

我想分别提取分子和分母,只考虑最后一个分数,所以要么是唯一的一个,要么是第二个,如果有两个。从来没有超过两个,他们之间是一些文字。你知道吗

我用这个来计算分母,在前斜杠之后提取任何数字:

print(df.data.str.extract('(?:.*\/(\d+)){0}.*\/(\d+)')[1])
0    2 
1    5 
2    7 
3    13
Name: 1, dtype: object

我没能让它对分子起作用,可能是因为它们包含小数的复杂性。 我得到的最接近的结果是,使用类似于上面的代码,再加上可能的小数处理:

df.data.str.extract('(?:((?:\d+\.)?\d+)\/){0}(?:((?:\d+\.)?\d+)\/)')[1]
0      1
1      2
2      6
3    8.2
Name: 1, dtype: object

它正确地提取小数点,但只返回第一个分数的结果。预计数字为1、4、6、10.12

在尝试了无数的代码变体之后,我被卡住了,希望能找到错误。你知道吗


Tags: nametestdfdataobjectextract数字分子
3条回答

一个更具熊猫风格的代码,带有一个简单的正则表达式来表示分数。你知道吗

import pandas as pd
test = {'data':[
    '1/2 lorem ipsum',
    '2/3 ipsum lorem 4/5',
    '6/7 lorem ipsum',
    '8.2/9 ipsum lorem 10.12/13']}
df = pd.DataFrame(test)
fractions = df.data.str.extractall('(\d+\.?\d*)/(\d+)').groupby(level=0).tail(1)
numerators = fractions[0].tolist()
denominators = fractions[1].tolist()
print("Numerators:",numerators,"\nDenominators",denominators)

输出

Numerators: ['1', '4', '6', '10.12'] 
Denominators ['2', '5', '7', '13']

我建议使用以下正则表达式:

(\d+(?:\.\d+)?)/(\d+(?:\.\d+)?)(?!.*\d+(?:\.\d+)?/\d+(?:\.\d+)?)

这将匹配一个分数,只要它后面没有同一字符串中的另一个分数。你知道吗

测试它live on regex101.com。你知道吗

说明:

(\d+(?:\.\d+)?) # Match a number, optionally followed by a decimal part
/               # Match a slash
(\d+(?:\.\d+)?) # Match another number
(?!             # only if it's not possible to match...
 .*             # any string
 \d+(?:\.\d+)?  # followed by a number,
 /              # a slash
 \d+(?:\.\d+)?  # and another number.
)               # (End of lookahead assertion)

你可以用

>>> df.data.str.extract(r'(?:.*\D)?(?<!\d\.)(\d+(?:\.\d+)?)/(\d+(?:\.\d+)?)')
       0   1
0      1   2
1      4   5
2      6   7
3  10.12  13

参见regex demo。你知道吗

细节

  • (?:.*\D)?-一个可选字符串,包含除换行符以外的任何0+个字符,尽可能多到非数字。。。你知道吗
  • (?<!\d\.)-前面不是一个数字和一个点。。。你知道吗
  • (\d+(?:\.\d+)?)-捕获组1:1+个数字和.和1+个数字的一个可选序列
  • /-a/
  • (\d+(?:\.\d+)?)-捕获组2:1+个数字和.和1+个数字的一个可选序列。你知道吗

如果需要分别获取字符串中最后一个分数的值请删除不必要的分组:

>>> df.data.str.extract(r'(?:.*\D)?(?<!\d\.)(\d+(?:\.\d+)?)/\d+(?:\.\d+)?')
       0
0      1
1      4
2      6
3  10.12
>>> df.data.str.extract(r'(?:.*\D)?(?<!\d\.)\d+(?:\.\d+)?/(\d+(?:\.\d+)?)')
    0
0   2
1   5
2   7
3  13

相关问题 更多 >