使用Python Regex最佳分隔符?

时间:2014-09-04 14:37:20

标签: python regex parsing

我正在尝试使用python中的re.split解析一行。以下是我正在尝试的示例行:

drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName_1
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName 1

我使用以下代码将每一行拆分成一个数组,并使用最后一个元素。

file_folder_names_parsed.insert(file_index, (re.split(r"\s", entry)))
print file_folder_names_parsed[file_index]

#The file/folder name is stored in the last element, lets index to that
num_elements_in_parsed_string = len(file_folder_names_parsed[file_index])
parsed_folder_names.insert(file_index, file_folder_names_parsed[file_index][num_elements_in_parsed_string-1])

现在的问题是,对于前两行,它工作正常,我能够使用以下条目填充列表:[FolderName,FolderName_1]

但是对于最后一个元素,我只得到[1]而不是[FolderName 1]。这是有道理的,因为中间有一个空格字符,我将其用作分隔符。不幸的是,我无法使用\ t(tab)作为我必须处理的字符串的正则表达式分隔符。

任何人都可以建议最后一个案例,我怎样才能获得[FolderName 1]而不是只获得[1]我目前得到的?

4 个答案:

答案 0 :(得分:3)

可能是这样的吗?

>>> import re
>>> s = '''drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName_1
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName 1'''
>>> re.findall(r'(?<=:\d{2})\s+(.*)(?=\n|$)', s)
['FolderName', 'FolderName_1', 'FolderName 1']

正则表达式解释:http://regex101.com/r/fM1nM4/1

答案 1 :(得分:3)

您应该匹配非空的空格字符序列,如下所示:\s+。此外,您应使用re.split()&#39; s maxsplit参数指定您愿意接受的最大分组数:

import re
lines = [
'drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName',
'drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName_1',
'drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName 1',
]

for entry in lines:
  filename = re.split(r'\s+', entry, maxsplit=8)[-1]
  print filename

在分割前8个项目后,re.split()会将该行的剩余部分作为单个项目返回。

但是,如果您只是使用whitepsace作为分隔符,那么根本不需要re.split()。只需使用更简单的str.split()

for entry in lines:
  filename = entry.split(None, 8)[-1]
  print filename

上述任何一个样本都会产生此输出:

FolderName
FolderName_1
FolderName 1

答案 2 :(得分:2)

根据没有数字和行尾锚点的空格分开,

>>> m = re.split(r'(?<!:\d{2} \d)\s+(?!\d+$)', 'drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName 1')
>>> m
['drwxr-xr-x', '2', 'user1', 'user1', '4096', 'Sep', '4', '14:23', 'FolderName 1']
>>> m = re.split(r'(?<!:\d{2} \d)\s+(?!\d+$)', 'drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 1 FolderName')
>>> m
['drwxr-xr-x', '2', 'user1', 'user1', '4096', 'Sep', '4', '14:23', '1 FolderName']

DEMO

模式说明:

  • (?<!:\d{2} \d)\s+(?!\d+$)

    (?<!....)称为负向后观,它断言空格之前的内容不满足此:\d{2} \d模式。 (?!\d+$)称为负向前瞻,断言,后面不是一个或多个数字和行尾$

答案 3 :(得分:2)

不使用split(),使用实际模式。

import re

listing = """drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName_1
drwxr-xr-x   2 user1    user1        4096 Sep  4 14:23 FolderName 1
asdasd
"""

listing_pattern = r"\s+".join([
    r"^(?P<type>\S)(?P<mode>\S+)",
    r"(?P<children>\d+)",
    r"(?P<user>\S+)",
    r"(?P<group>\S+)",
    r"(?P<size>\S+)",
    r"(?P<time>.*\d:\d\d)",
    r"(?P<filename>.*)",
])

for entry in iter(listing.splitlines()):
    match = re.match(listing_pattern, entry)
    if match:
        print match.group("filename")

打印

FolderName
FolderName_1
FolderName 1

正如@tripleee在评论中指出的那样,你不应该首先解析ls的输出。在上面,链接中最弱的链是<time>组(想想上午/下午时间表示)。


如果您对文件名之前的列不感兴趣,那么较短的正则表达式就足够了:

listing_pattern = r".*?:\d\d (?P<filename>.*)"

同样,时间以":"后跟两位数结尾的假设是该方法的弱点。