【问题标题】:How to parse a string which may or maynot contain newline in python?如何解析在python中可能包含或不包含换行符的字符串?
【发布时间】:2021-02-23 04:16:36
【问题描述】:

我有一个像这样用逗号分隔的文本数据集-

TABLE DATA IS ALPHANUMERIC
TABLE IS UNSORTED
VALUES ARE ( A S Q M N C H )
SEARCH IS LINEAR
,
TABLE DATA IS ALPHANUMERIC
TABLE IS SORTED
VALUES ARE ( 0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E )
SEARCH IS NONLINEAR
,
TABLE DATA IS ALPHANUMERIC
TABLE IS SORTED
VALUES ARE ( 02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05 P 
           17 T 08 K 09 E )
SEARCH IS LINEAR

示例输出将如下所示: sample output

我必须解析数据以形成一个 pandas 数据框,其中包含 is_alphanumeric、已排序/未排序和值等列。 我已根据逗号分隔符分隔文件并在每个项目中运行 for 循环。

value_name=[]
vname = re.search('VALUES ARE \( (.*) \)', line)
value_name.append(vname.group(1).replace("' '", "''"))

但是这个正则表达式只获取单行中的值。我无法获取那些分布在多行中的值。这里的一个数据项显示 2 行值,也可以有 3 行。在这种情况下我该如何获取。在这种情况下如何删除换行符并删除多余的空格?

【问题讨论】:

  • 你能发布minimal reproducible example,包括样本输入和输出吗?即您是否从文件中读取此内容?预期的输出是什么?如果我们知道预期的输出是什么,这可能更容易使用字符串方法解析。
  • 是的,我从文本文件中读取了输入,即我在问题中给出的格式。我附上了一个示例输出。基本上,无论括号内的值是什么,我都需要获取它。
  • 如果“逗号”分隔的不是行元素而是段落,那么您可以将所有感兴趣的行解析为单行或行列表以使用re 方法进行检查

标签: python python-3.x regex pandas parsing


【解决方案1】:

@PatrickArtner 提供了正则表达式解决方案,只是想使用字符串方法添加解决方案

dataset = """TABLE DATA IS ALPHANUMERIC
TABLE IS UNSORTED
VALUES ARE ( A S Q M N C H )
SEARCH IS LINEAR
,
TABLE DATA IS ALPHANUMERIC
TABLE IS SORTED
VALUES ARE ( 0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E )
SEARCH IS NONLINEAR
,
TABLE DATA IS ALPHANUMERIC
TABLE IS SORTED
VALUES ARE ( 02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05 P 
           17 T 08 K 09 E )
SEARCH IS LINEAR"""

def parse_chunk(chunk):
   data = {}
   headers = {'TABLE DATA IS ': 'DATA TYPE', 'TABLE IS ': 'IS_SORTED',
              'SEARCH IS ': 'SEARCH'}
   for line in chunk:
       if line.startswith('VALUES ARE ( '):
           data['VALUES'] = [line[13:-2]]
       elif line.startswith(' '):
          data['VALUES'].append(line.strip(' )'))
       else:
          for prefix, key in headers.items():
              if line.startswith(prefix):
                  data[key] = line[len(prefix):]
                  break
   data['VALUES'] = ' '.join(data['VALUES']) # combine all values chunks
   return data

      
import pandas as pd
data = [parse_chunk(chunk.splitlines()) for chunk in dataset.split('\n,\n')]
print(data)
df = pd.DataFrame(data)
print(df)

输出

[{'DATA TYPE': 'ALPHANUMERIC', 'IS_SORTED': 'UNSORTED', 'VALUES': 'A S Q M N C H', 'SEARCH': 'LINEAR'}, {'DATA TYPE': 'ALPHANUMERIC', 'IS_SORTED': 'SORTED', 'VALUES': "0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E", 'SEARCH': 'NONLINEAR'}, {'DATA TYPE': 'ALPHANUMERIC', 'IS_SORTED': 'SORTED', 'VALUES': "02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05  17 T 08 K 09 E", 'SEARCH': 'LINEAR'}]
      DATA TYPE IS_SORTED                                             VALUES     SEARCH
0  ALPHANUMERIC  UNSORTED                                      A S Q M N C H     LINEAR
1  ALPHANUMERIC    SORTED     0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E  NONLINEAR
2  ALPHANUMERIC    SORTED  02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05  17 T ...     LINEAR

【讨论】:

    【解决方案2】:

    您可以为影响匹配方式的正则表达式方法提供标志 - 我提供 're.DOTALL' 所以'.' 也可以匹配换行符并稍微调整您的值的模式:

    • 拆分为','
    • 通过正则表达式提取到字典中
      • split + strip + join 每个数据行 if '\n' in 删除换行符和前导空格
    • 设置为 DataFrame

    text = """TABLE DATA IS ALPHANUMERIC
    TABLE IS UNSORTED
    VALUES ARE ( A S Q M N C H )
    SEARCH IS LINEAR
    ,
    TABLE DATA IS ALPHANUMERIC
    TABLE IS SORTED
    VALUES ARE ( 0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E )
    SEARCH IS NONLINEAR
    ,
    TABLE DATA IS ALPHANUMERIC
    TABLE IS SORTED
    VALUES ARE ( 02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05 P 
              17 T 08 K 09 E )
    SEARCH IS LINEAR"""
    

    代码:

    import re
    import pandas as pd
    
    
    # map a regexpattern to the columnname in the df to store its info 
    patterns = {"(IS ALPHANUMERIC)": "alphanum",
                "(IS SORTED)": "sorting",
                "(IS UNSORTED)": "sorting",
                "(IS NONLINEAR)": "search",
                "(IS LINEAR)": "search",
                "VALUES ARE \((.+?)\)": "values"}
    
    data = []
    df = pd.DataFrame(columns=["alphanum", "sorting", "search", "values"])
    
    for i,parts in enumerate(text.split(",")):
        print()
        found = {"alphanum":None, "sorting":None, "search":None, "values":None}
        for pattern, heading in patterns.items():
            match = re.search(pattern, parts, flags=re.DOTALL)
            if match:
                found[heading] = ' '.join(map(str.strip, match[1].split("\n")))
        df.loc[i] = found
    print(df)
    

    输出:

              alphanum      sorting        search                                             values
    0  IS ALPHANUMERIC  IS UNSORTED     IS LINEAR                                      A S Q M N C H
    1  IS ALPHANUMERIC    IS SORTED  IS NONLINEAR     0A M 0B S 0A D 01 ' ' 04 N 05 P 07 T 08 K 09 E
    2  IS ALPHANUMERIC    IS SORTED     IS LINEAR  02 M 0f S 0A M 0B S 0A D 01 ' ' 0D N 05 P 17 T...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-30
      相关资源
      最近更新 更多