使用正则表达式拆分为列

时间:2020-05-10 04:04:15

标签: python regex pandas valueerror

我非常需要帮助,我想使用regex(python)将数据拆分为列,它必须使用正则表达式

Jan  9 01:04:49 syntax sshd(pam_unix)[21354]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=120-123-141-4.hinet-ip.hinet.com  

Jul 10 04:17:11 syntax su(pam_unix)[95367]: session opened for user abc by (uid=0)

May  1 14:06:19 syntax su(pam_unix)[95367]: session closed for user abc

Oct 23 18:08:26 syntax logrotate: ALERT exited abnormally with [1]

Jun 14 21:42:52 syntax su(pam_unix)[95367]: session opened for user cbx by (uid=0)

假定的输出

Supposed Output

它实际上来自URL,我将其放入pandas dataFrame中并尝试使用re.split,但它给了我错误

*ValueError: 1 columns passed, passed data had 24 columns*

希望我能得到我需要的输出吗?

5 个答案:

答案 0 :(得分:1)

因此您可以像这样创建一个命名的正则表达式,

r'(?P<Timestamp>\w{3}\s+\d{1,2}\s\d{1,2}:\d{2}:\d{2})\s(?P<A1>\w+)\s(?P<A2>[\S]+)\:\s(?P<A3>.*)'

如果上述正则表达式不起作用,则可以创建自己的正则表达式并在regex101.com上进行测试

使用您提供的示例here,您可以了解我的工作方式。

然后使用str.extract将命名组更改为列名。

代码看起来像

import pandas as pd

df = pd.DataFrame(data=["Jan  9 01:04:49 syntax sshd(pam_unix)[21354]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=120-123-141-4.hinet-ip.hinet.com",
"Jul 10 04:17:11 syntax su(pam_unix)[95367]: session opened for user abc by (uid=0)",
"May  1 14:06:19 syntax su(pam_unix)[95367]: session closed for user abc"], columns=["value"])
print(df)

在控制台上,

 value
0  Jan  9 01:04:49 syntax sshd(pam_unix)[21354]: ...
1  Jul 10 04:17:11 syntax su(pam_unix)[95367]: se...
2  May  1 14:06:19 syntax su(pam_unix)[95367]: se...

添加此选项可将value列拆分为所需的列,

pattern = r'(?P<Timestamp>\w{3}\s+\d{1,2}\s\d{1,2}:\d{2}:\d{2})\s(?P<A1>\w+)\s(?P<A2>[\S]+)\:\s(?P<A3>.*)'

df1 = df['value'].str.extract(pattern, expand=True)
print(df1)

在控制台上,

     Timestamp      A1                     A2                                                 A3
0  Jan  9 01:04:49  syntax  sshd(pam_unix)[21354]  authentication failure; logname= uid=0 euid=0 ...
1  Jul 10 04:17:11  syntax    su(pam_unix)[95367]             session opened for user abc by (uid=0)
2  May  1 14:06:19  syntax    su(pam_unix)[95367]                        session closed for user abc

希望这会有所帮助,干杯!

答案 1 :(得分:1)

按以下方式使用正则表达式

数据

 df=pd.DataFrame({'Text':['Jan  9 01:04:49 syntax sshd(pam_unix)[21354]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=120-123-141-4.hinet-ip.hinet.com','Jul 10 04:17:11 syntax su(pam_unix)[95367]: session opened for user abc by (uid=0)','May  1 14:06:19 syntax su(pam_unix)[95367]: session closed for user ab']})

regex = ([A-Za-z]+\s+\d+\s+\d+:\d+:\d+)\s+|(?<=\])[:\s+]+|(?<=[x])\s+

df2=df.Text.str.split('([A-Za-z]+\s+\d+\s+\d+:\d+:\d+)\s+|(?<=\])[:\s+]+|(?<=[x])\s+', n=3, expand=True)

df2.rename(columns=({0:'DROP1',1:'Timestamp', 2:'A1', 3:'DROP', 4:'A2', 5:'DROP2',6:'A3'}),inplace=True)#Rename columns

df2.drop(columns=['DROP2','DROP1','DROP'],inplace=True)#Drop unwanted columns

基本上;

(?<=\])[:\s+]+]:之后的空格分隔

或-|

(?<=[x])\s+x之后的空格分隔

或-|

([A-Za-z]+\s+\d+\s+\d+:\d+:\d+)\s+拆分timestamp

结果

enter image description here

答案 2 :(得分:0)

下面的正则表达式可以拆分该语句。必填列将在捕获组中。

(.*:\d\d)\s(.*?)\s(.*?:)\s(.*)

检查以下链接以供参考:

regexr.com/549bm

例如,第二条记录将被拆分为

7月10日04:17:11

语法

su(pam_unix)[95367]:

会话由(uid = 0)为用户abc打开

答案 3 :(得分:0)

刚开始时,“它必须使用正则表达式”毫无道理没有任何意义-出于您的目的,找出几个拆分将变得更快,并且可能类似于它的健壮性。话虽这么说...

如果要使用正则表达式解析这些类似于syslog的消息,则只需找出4种格式中的至少3种,然后将它们与(命名的)组结合在一起即可。

我们希望最终得到这样的结果:

re_log = rf'(?P<date>{re_date}) (?P<device>{re_device}) (?P<source>{re_source}): (?P<message>{re_message})'

请注意各组之间以及冒号之间的空格。

由于该消息不太可能遵循任何可用的模式,因此必须将其用作通配符:

re_message = r'.*'

同样,该设备希望是有效的设备ID或主机名(例如,不能有空格,只能是字母数字和破折号):

re_device = r'[\w-]+'

我们可以使用datetime或time或某种解析来获取日期的正式解析,但我们并不在乎,因此,让我们大致匹配您的格式。我们不知道您的日志格式是使用前导零还是将其排除在外,因此我们可以:

re_date = r'\w{3} \d{1,2} \d{1,2}:\d{2}:\d{2}'

源代码是有点结构化的,但是只要它没有空格,我们就可以在所有内容上进行匹配,因为我们在re_log表达式中有一个冒号来捕获它:

re_source = r'[^ ]+'

最后,尝试一下可以为我们提供一些可以应用于您的邮件的信息

>>> import re
>>> eg = "Oct 23 18:08:26 syntax logrotate: ALERT exited abnormally with [1]"
>>> m = re.match(re_log, eg)
>>> m.groupdict()
{'date': 'Oct 23 18:08:26',
 'device': 'syntax',
 'source': 'logrotate',
 'message': 'ALERT exited abnormally with [1]'}

答案 4 :(得分:0)

解决方案

您需要将以下正则表达式模式与pandas.Series.str.findall()一起使用,以快速,轻松地获取它。
我还做了一个便捷功能process_logdata(),因此您可以直接使用它。便捷功能位于此答案的底部。

df = process_logdata(log_file_name='logfile.txt')
print(df)

enter image description here

逻辑

这是便利功能process_logdata()的逻辑。

# regex pattern
pattern = '\s*(\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(\S+)\s+(\S+?:)\s+(.*)'

# read log file
df = pd.read_csv('logfile.txt', header=None).rename(columns={0: 'logline'})
# process data
ds = df.logline.str.strip().str.findall(pattern)
a = np.array([list(e) for e in ds]).reshape(ds.size,-1)
# finalize processed data as a dataframe
df = pd.DataFrame(a, columns=['Timestamp', 'A1', 'A3', 'A3'])
print(df)

示例

在这里,我们使用虚拟数据(以字符串形式提供)。首先,我们将其加载到熊猫数据框中,然后对其进行处理。

import numpy as np
import pandas as pd
import re
from io import StringIO 

s = """
Jan  9 01:04:49 syntax sshd(pam_unix)[21354]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=120-123-141-4.hinet-ip.hinet.com  

Jul 10 04:17:11 syntax su(pam_unix)[95367]: session opened for user abc by (uid=0)

May  1 14:06:19 syntax su(pam_unix)[95367]: session closed for user abc

Oct 23 18:08:26 syntax logrotate: ALERT exited abnormally with [1]

Jun 14 21:42:52 syntax su(pam_unix)[95367]: session opened for user cbx by (uid=0)
"""
s = re.sub('\n\s*\n', '\n', s).strip()
#print(s)

df = pd.read_csv(StringIO(s), header=None).rename(columns={0: 'logline'})
pattern = '\s*(\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(\S+)\s+(\S+?:)\s+(.*)'
ds = df.logline.str.strip().str.findall(pattern)
a = np.array([list(e) for e in ds]).reshape(ds.size,-1)
df = pd.DataFrame(a, columns=['Timestamp', 'A1', 'A3', 'A3'])
print(df)

输出

enter image description here

便捷功能

import numpy as np
import pandas as pd
import re

def process_logdata(log_file_name):
    """Returns a dataframe created from the log file.
    """
    ## Define regex pattern
    pattern = '\s*(\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+(\S+)\s+(\S+?:)\s+(.*)'

    ## Read log file
    df = (pd
          .read_csv(log_file_name, header=None)
          .rename(columns={0: 'logline'})
    )
    ## Process data
    ds = df['logline']str.strip().str.findall(pattern)
    a = np.array([list(e) for e in ds]).reshape(ds.size,-1)
    ## Finalize processed data as a dataframe 
    df = pd.DataFrame(a, columns=['Timestamp', 'A1', 'A3', 'A3'])
    return df