从 Python 中的字符串中提取信息并返回列表

Extracting infor from a string in Python and returning a list

我正在研究一个大型数据集,我正在将我的分析从 Matlab/Octave 转移到 Python。这些文件按 folder/directories 组织,每个目录名称包含有关数据的基本信息。在 Matlab 中,我从文件夹名称中提取该信息。我想在 Python 中做同样的事情。我知道一点Python,但我绝对不是功夫高手

MWE

from re import split

file_list = ['15L-0.3', '16L-0.4_redo', '15L-0', '16L-redo']
s_f = lambda x: float(x) if isinstance(x,(int, float))\
    else [split('[^0-9.]+',x,1)[0], split('0[.0-9]*',x,1)[1]]
array = [[i, [float(i.split('L',1)[0]),
    s_f(i)]]for i in file_list]

前面的代码不适用于 file_list 的所有元素,并且 lambda 中的 return 未附加到数组。我将标准 split()re.split() 版本混合使用。但我认为标准版不接受正则表达式。

我需要一个数组,一个列表列表,其中对于 file_list 的每个元素,我得到文件夹名称,即 file_list 中的元素。 thaat 子列表的第二个元素是 16 之前的数字的数组,然后它可以有 1 或 2 个其他元素。 L 之后的 0 和 1 之间的数字,它并不总是存在,以及这个数字之后的任何内容,如果数字不存在,甚至是 L 本身。

对于第一个元素 [15, 0.3]

第二次 [16, 0.4, '_redo']

第三次 [15, 0]

第四个 [16, '-redo']

我有几个逻辑阶段,因为我的实际字符串更长并且有多个参数。我可以将其拆分为后缀 0 和 1 and/or 之间的数字是否存在或存在,但我想看看是否有办法使这个通用

我为此编写了 lambda 函数。如果输出是单个数字或字符串,它就可以工作。当我需要为外部列表输出 2 个元素时出现问题。

如果我命名事物的语法不正确,我们深表歉意。我可能会混淆列表和数组

欢迎任何评论、更正或建议

您可以将 re.split 与前瞻性正则表达式一起使用,并将列表理解与辅助函数一起使用:

import re

regex = re.compile('[-_](?=\d)|(?=[-_]\D)')

def toint(n):
    n2 = n.rstrip('L')
    if n2.replace('.', '', 1).isnumeric():
        return float(n2) if '.' in n2 else int(n2)
    else:
        return n

[[toint(i) for i in l] for l in map(regex.split, file_list)]

输出:

[[15, 0.3], [16, 0.4, '_redo'], [15, 0], [16, '-redo']]

我认为这里更好的解决方案是实际寻找您想要匹配的模式。

我认为这会解决您的问题,并且更容易调试:

import re

file_list = ['15L-0.3', '16L-0.4_redo', '15L-0', '16L-redo']
new_file_list = []
for file in file_list:
    split_file = re.findall(r'(?:\d+(?:\.\d+)*|[-_]redo)', file)
    new_file_list.append(split_file)

print(new_file_list)

输出:

[['15', '0.3'], ['16', '0.4', '_redo'], ['15', '0'], ['16', '-redo']]

您还可以将以下解决方案与正则表达式模式结合使用,捕获所有三个部分,最后两个部分是可选的:

import re,ast

file_list = ['15L-0.3', '16L-0.4_redo', '15L-0', '16L-redo']
rx = re.compile(r'^(\d+)L(?:-(\d+(?:\.\d+)?))?([_-].*)?$')
array = []
for i in file_list:
    m = rx.search(i)
    if m:
        arr = list(m.groups())
        arr[0] = int(arr[0]) # This is an int
        if arr[1]: # If Group 2 matched, it is either an int or float
            arr[1] = ast.literal_eval(arr[1]) # Parse the second number as int or float
        array.append([x for x in arr if x is not None]) # Remove any None values

print (array)
# => [[15, 0.3], [16, 0.4, '_redo'], [15, 0], [16, '-redo']]        

参见Python demo. Here is the regex demo详情:

  • ^ - 字符串开头
  • (\d+) - 第 1 组:一个或多个数字(因此,我们可以安全地使用 int(arr[0])
  • L - L 字母
  • (?:-(\d+(?:\.\d+)?))? - 一个可选的序列
    • - - 一个连字符
    • (\d+(?:\.\d+)?) - 第 2 组:一个或多个数字,然后是 . 和一个或多个数字的可选序列
  • ([_-].*)? - 可选的第 3 组:_- 然后是任何字符(除了没有 re.DOTALL 标志的换行字符)直到字符串。