从 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
标志的换行字符)直到字符串。
我正在研究一个大型数据集,我正在将我的分析从 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
标志的换行字符)直到字符串。