使用正则表达式、循环、枚举解析复杂的字符串列表,以生成 pandas 数据帧

Parsing complicated list of strings using regex, loops, enumerate, to produce a pandas dataframe

我有一长串很多元素,每个元素都是一个字符串。请参阅以下示例:

data = ['BAT.A.100',   'Regulation 2020-1233',   'this is the core text of', 'the regulation referenced ',
'MOC to BAT.A.100', 'this', 'is', 'one method of demonstrating compliance to BAT.A.100', 

 'BAT.A.120',   'Regulation 2020-1599',   'core text of the regulation ...', ' more free text','more free text', 

 'BAT.A.145',   'Regulation 2019-3333',   'core text of' ,'the regulation1111',
'MOC to BAT.A.145', 'here is how you can show compliance to BAT.A.145','more free text', 
'MOC2 to BAT.A.145', ' here is yet another way of achieving compliance']

我想要的输出最终是一个 Pandas DataFrame,如下所示:

由于可能需要连接字符串,我首先使用 ## 将所有元素连接到单个字符串以分隔已连接的文本。 我要使用所有正则表达式,因为否则会有很多条件需要检查。

re_req = re.compile(r'##(?P<Short_ref>BAT\.A\.\d{3})'
                    r'##(?P<Full_Reg_ref>Regulation\s\d{4}-\d{4})'
                    r'##(?P<Reg_text>.*?MOC to |.*?(?=##BAT\.A\.\d{3})(?!))'
                    r'(?:##)?(?:(?P<Moc_text>.*?MOC2 to )(?P<MOC2>(?:##)?.*?(?=##BAT\.A\.\d{3})(?!)|.+)'
                    r'|(?P<Moc_text_temp>.*?(?=##BAT\.A\.\d{3})(?!)))')

final_list = []
for match in re_req.finditer("##" + "##".join(data)):
    inner_list = [match.group('Short_ref').replace("##", " "),
                  match.group('Full_Reg_ref').replace("##", " "),
                  match.group('Reg_text').replace("##", " ")]
    if match.group('Moc_text_temp'): # just Moc_text is present
        inner_list += [match.group('Moc_text_temp').replace("##", " "), ""]
    elif match.group('Moc_text') and match.group('MOC2'): # both Mock_text and MOC2 is present
        inner_list += [match.group('Moc_text').replace("##", " "), match.group('MOC2').replace("##", " ")]
    else: # neither Moc_text nor MOC2 is present
        inner_list += ["", ""]
    final_list.append(inner_list)
final_df = pd.DataFrame(final_list, columns=['Short_ref', 'Full_Reg_ref', 'Reg_text', 'Moc_text', 'MOC2'])

正则表达式的第一行和第二行与您之前发布的相同,并标识了前两列。

在正则表达式的第三行,r'##(?P<Reg_text>.*?MOC to |.*?(?=##BAT\.A\.\d{3})(?!))' - 将 MOC 之前的所有文本匹配到 Short_ref 或匹配下一个 Reg_text 之前的所有文本。 (?=##BAT\.A\.\d{3})(?!) 部分是将文本变为 Short_ref 模式,如果 Short_ref 不是当前的 Reg_text。

第四行是针对 Moc_textMOC2 都存在的情况,or 第五行是针对仅存在 Moc_text 的情况。这部分正则表达式与第三行类似。

最后使用 finditer 遍历所有匹配项并构建数据帧的行 final_df: