2014-09-04 2 views
0

Я пытаюсь разобрать строку, используя re.split в python. Вот пример строки Я пытаюсь работать на:Python Regex лучший разделитель для использования?

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]

Но для последнего элемента, вместо получая [FolderName 1], я получаю только [1]. Это имеет смысл, поскольку между ними есть пробельный символ, который я использую в качестве разделителя. К сожалению, я не могу использовать \ t (tab) как разделитель регулярных выражений для строки, с которой мне приходится иметь дело.

Может ли кто-нибудь предложить для последнего случая, как я могу получить [FolderName 1] вместо того, чтобы просто получить [1], который я сейчас получаю?

+0

Вы можете написать шаблон, который будет соответствовать каждой части строки отдельно, а не пытаться «разбить» и индексировать. – jonrsharpe

+3

[Не разбирайте 'ls' output] (http://mywiki.wooledge.org/ParsingLs) в первую очередь. – tripleee

+0

* Рядом *: В вашем коде выше выражение 'file_folder_names_parsed [file_index] [num_elements_in_parsed_string-1]' равнозначно 'file_folder_names_parsed [file_index] [- 1]'. В общем, всякий раз, когда вы хотите получить конечный элемент списка, используйте 'xxx [-1]', а не 'xxx [len (xxx) -1]'. –

ответ

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+$)

    (?<!....) называется негативный lookbehind, который утверждает, что предшествует пространству, не соответствует этому шаблону :\d{2} \d. (?!\d+$) называется отрицательным опережения, который утверждает, что за ним следует не один или более цифр и конец линии якоря $

+0

Спасибо Авинаш, это было полезно. Но в случае, когда я сталкиваюсь с случаем, когда мне приходится иметь дело с [1 FolderName], он будет анализировать только [FolderName] и не использовать [1], который был фактически частью всего имени папки. Есть ли способ, я могу позволить регулярному выражению также создавать имена файлов, созданные с пробелами, но начиная с числа? – c0d3rz

+0

@ c0d3rz updated ... ' –

+0

Или используйте 'regex.split (r' (?

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'] 

Regex объяснение: http://regex101.com/r/fM1nM4/1

3

Вы должны соответствовать непустая последовательность пробельных символов, например, так: \s+. Кроме того, следует указать максимальное количество расколов вы готовы принять, с re.split() «ы 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() возвращает остаток строки в качестве отдельного пункта ,

Но, если вы просто собираетесь использовать белую одежду в качестве разделителя, вам не нужно re.split(). Просто используйте простой str.split():

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

Любой из образцов выше производить этот вывод:

FolderName 
FolderName_1 
FolderName 1 
+0

Спасибо большое Роб. Это был интересный подход ... – c0d3rz

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> (думайте о времени/pm).


Если вы не заинтересованы в колоннах перед именем файла, короче регулярное выражение будет достаточно:

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

Опять же, предположение о том, что время заканчивается ":" следуют две цифры в слабое место этого подхода.

Смежные вопросы