簡體   English   中英

使用正則表達式拆分為列

[英]Using regular expression to split into columns

我迫切需要幫助有一個我想使用正則表達式(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)

假設 output

假定輸出

它實際上來自 url,我把它變成了 pandas dataFrame 並嘗試使用 re.split 但它給了我錯誤

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

希望我能得到我需要的 output 嗎?

所以你可以像這樣創建一個命名的正則表達式,

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上進行測試

您可以使用您在此處提供的示例了解我是如何做到的。

然后使用 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...

添加此以將值列拆分為您需要的列,

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

希望這會有所幫助,干杯!

使用正則表達式如下

數據

 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']})

正則表達式= ([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

結果

在此處輸入圖像描述

下面的正則表達式可以拆分語句。 必需的列將在捕獲組中。

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

檢查以下鏈接以供參考:

regexr.com/549bm

例如,第二條記錄將被拆分為

7月10日 04:17:11

句法

蘇(pam_unix)[95367]:

session 由 (uid=0) 為用戶 abc 打開

剛開始,“它必須使用正則表達式”沒有任何理由沒有任何意義 - 出於您的目的,一些拆分將更快地弄清楚並且可能在它的健壯性方面相似。 話雖如此...

如果您想使用正則表達式來解析這些類似 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]'}

解決方案

您需要使用以下正則表達式模式以及pandas.Series.str.findall()來快速輕松地獲取它。
我還做了一個方便的 function : process_logdata()所以你可以直接使用它。 便利 function 可在此答案的底部找到。

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

在此處輸入圖像描述

邏輯

這是方便 function, 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)

例子

這里我們使用虛擬數據(以字符串形式提供)。 首先,我們將其加載到 pandas dataframe 中,然后對其進行處理。

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)

Output

在此處輸入圖像描述

方便 Function

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM