pandas 如何处理方括号 [] 以及如何避免这种情况?

问题描述

我必须阅读包含以下行的 tomcat 访问日志:

    [06/Nov/2020:00:43:04 +0200] /wsi/services/ServicesReadRequest  2265 10.101.101.101 200 21

尝试将文件读取为 csv,将所有列设置为字符串类型

    import pandas as pd 

    headers = ['Timestamp','Command','IPAddr','Blank01','Blank02','Bytes','HTTPResult','elapsedtime']
    dtypes = {'Timestamp': 'str','Command': 'str','IPAddr': 'str','Blank01' : 'str','Blank02' : 'str','Bytes': 'str','HTTPResult': 'str','elapsedtime': 'str'} 

    df = pd.read_csv(fpath,delimiter=' ',header=None,names=headers,dtype=dtypes,warn_bad_lines=True,error_bad_lines=False)

发生的事情是时间戳周围的方括号是由熊猫专门处理的

    df['Timestamp'].head()

显示

    [06/Nov/2020:00:43:04 +0200] /wsi/services/ServicesReadRequest

如果我试图剪断字符串,它看起来像方括号的部分被忽略

    df["Timestamp"].apply(lambda x: x[1:6]).head()

结果:

    [06/Nov/2020:00:43:04 +0200] /wsi/s

如果我手动删除方括号,那么它会按预期工作(尽管时区与时间戳分开,但这是因为它之间有空格)。 现在的问题是如何在没有任何预处理的情况下解析文件? 是否有不包含此类副作用的 read_csv 替代方案?

解决方法

我使用字典和正则表达式替换来解析日期时间组件中的字符串。 see(can you write a str.replace() using dictionary values in Python?) 然后将字符串转换为日期时间,然后添加时间增量

 data=["06/Nov/2020:00:43:04 +0200"]
 df=pd.DataFrame(data,columns=['date'])
 def MonthToNum(val):
      dictMonth={'Jan':'1','Feb':'2','Mar':'3','Apr':'4','May':'5','Jun':'6','Jul':'7','Aug':'8','Sep':'9','Oct':'10','Nov':'11','Dec':'12'}
      pattern = '|'.join(sorted(re.escape(k) for k in dictMonth))
      retval=re.sub(pattern,lambda m: dictMonth.get(m.group(0)),val,flags=re.IGNORECASE)
     return retval

 df['date']=df['date'].apply(lambda x: pd.to_datetime(MonthToNum(x[0:11])+" "+x[12:20]) + timedelta(int(x[20:24])))
 print(df)
 print(type(df['date']))

输出:

  date
0 2020-06-13 00:43:04
,

解决方案是在 read_csv 命令中添加 index_col=False 并添加更多列, 时间戳可以转换为日期时间

    headers = ['Timestamp','Timezone','Command','Blank01','IPAddr','Blank02','Blank03','Bytes','HTTPResult','ElapsedTime']
    dtypes = {'Timestamp': 'str','Timezone' : 'str','Command': 'str','Blank01' : 'str','IPAddr': 'str','Blank02' : 'str','Blank03' : 'str','Bytes': 'str','HTTPResult': 'str','ElapsedTime': 'str'}

    df = pd.read_csv(fpath,delimiter=' ',index_col=False,header=None,names=headers,dtype=dtypes,warn_bad_lines=True,error_bad_lines=False)
       
    df['Timestamp'] =  pd.to_datetime(df['Timestamp'],format='[%d/%b/%Y:%H:%M:%S',errors='coerce')
    idx4 = df['Timestamp'].isna();