正则表达式使用python比较和提取字母字符

时间:2018-12-14 03:20:22

标签: python regex dataframe

嗨,我有一个数据集,如下所示:

Format,Message,time
A,ab@1 yl@5 rd@20 pp@40,3
B,bc@1 gn@7 yl@20 ss@25 rd@50, 21
C,cc@1 yl@9 rd@20, 22

我想使用从Messages的yl和rd中提取的数字,然后在其数字(例如yl @ 5 ---> 5)和时间列的数字之间进行数字比较。因此,如果将第1行,第3行与第5行和第20行进行比较,那么如果它小于两个元素,则将赋值为g。如果时间为7,则将分配值y,同样,如果其值为20或更高,则将其分配为r。

所以会像

Format,Message,time,status
A,ab@1 yl@5 rd@20 pp@40,3,g
B,bc@1 gn@7 yl@20 ss@25 rd@50,21,y
C,cc@1 yl@9 rd@20,22,r

2 个答案:

答案 0 :(得分:2)

您的问题实际上是很多问题。从“ dataframe”标签看来,您正在使用熊猫来进行此操作。您要查询的正则表达式可能会增加数字“ yl”和“ rd”(如果有的话,我假设它们始终存在)。但是正则表达式通常不进行数学或数值比较,因此仅占第三位。

与'yl'的数值匹配的正则表达式(假定为整数,而不是浮点数):

r'yl@(\d+)'

您可以在单个表达式中提取它们,但前提是它们始终处于相同顺序,或者成为复杂的正则表达式。

要确保仅匹配yl@5,但不能匹配xyl@5,则可以对开始(要求空格或行首)和结束(要求空格或行尾)添加一些限制):

r'(^|\s)yl@(\d+)($|\s)'

或者,如果您遇到yla:yl这样的名称分隔的情况,也可以添加它:

r'(^|\s)([a-z]+:)?l@(\d+)($|\s)'

但是,所有这些只是使用正则表达式语言构建更具体的表达式。 RegexBuddy是我喜欢使用(没有从属关系)的一个非常好的写正则表达式的工具,但是也有相当不错的在线工具,例如https://regex101.com/

在代码示例中使用,基本上可以完成您建议的操作:

import re
from pandas import DataFrame

df = DataFrame({
    'Format': ['A', 'B', 'C'],
    'Message': ['ab@1 yl@5 rd@20 pp@40', 'bc@1 gn@7 yl@20 ss@25 rd@50', 'cc@1 yl@9 rd@20'],
    'time': [3, 21, 22]
})


def determine_status(row):
    def find(tag, message):
        match = re.search(rf"{tag}@(\d+)", message)
        if match:
            return match.group(1)
        else:
            raise ValueError(f'{tag} not in message.')

    yl = int(find('yl', row['Message']))
    rd = int(find('rd', row['Message']))

    time = int(row['time'])
    if time < yl < rd:
        return 'g'
    if yl <= time < rd:
        return 'y'
    return 'r'


df['status'] = df.apply(determine_status, axis=1)

print(df)

find函数使用一个标记和一条消息,并使用正则表达式为消息中的标记生成数值。

determine_status函数就是这样做的-它期望从DataFrame中获取一行,并将使用Messagetime列来确定状态并返回状态。

df.apply然后用于创建新的status列,并为DataFrame中的每一行填充determine_status的结果。

您没有指定要使用的Python版本,但是如果它是Python 3.6之前的版本,则会发现f'{tag} not in message.'之类的表达式不起作用-而是使用诸如'{tag} not in message.'.format(tag=tag)

答案 1 :(得分:0)

我认为,这可以通过内置的字符串函数来完成。试试吧!

def f(mess):
    p1 = mess.find('yl')
    p2 = mess.find('rd')
    return int(mess[p1+3:].split(' ')[0]),int(mess[p2+3:].split(' ')[0])

df['vals'] =df['Message'].apply(f) 

df['status'] = df.apply(lambda row:  'g' if min(row['vals']) > row.time \
                        else 'y' if row.vals[1]>row.time  \
                        else 'r', axis=1)

print(df)

输出:

  Format                  Message  time      vals status
0      A    ab@1 yl@5 rd@20 pp@40     3   (5, 20)      g
1      B  bc@1  yl@20 ss@25 rd@50    21  (20, 50)      y
2      C          cc@1 yl@9 rd@20    22   (9, 20)      r