2016-01-03 2 views
4

Я пытаюсь вытащить данные, содержащиеся в FTP LIST.Python Регулярное выражение Lookahead overhooting pattern

Я использую регулярное выражение в Python 2.7.

test = "-rw-r--r-- 1 owner group  75148624 Jan 6 2015 somename.csv-rw-r--r-- 1 owner group  223259072 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   4041411 Jun 5 2015 somename-adjusted.csv-rw-r--r-- 1 owner group   2879228 May 13 2015 somename.csv-rw-r--r-- 1 owner group  11832668 Feb 13 2015 somename.csv-rw-r--r-- 1 owner group   1510522 Feb 19 2015 somename.csv-rw-r--r-- 1 owner group   2826664 Feb 25 2015 somename.csv-rw-r--r-- 1 owner group   582985 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   212427 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   3015592 Feb 27 2015 somename.csv-rw-r--r-- 1 owner group   103576 Feb 27 2015 somename-corrected.csv" 

(теперь без форматирования коды, так что вы можете увидеть его без прокрутки)

теста = «-rw-р - r-- 1 владелец группы 75148624 6 января 2015 somename.csv-RW-р --r-- 1 группа владельцев 223259072 26 февраля 2015 г. somename.csv-rw-r - r-- 1 группа владельцев 4041411 5 июня 2015 г. somename-adjust.csv-rw-r - r-- 1 группа владельцев 2879228 май 13 2015 somename.csv-rw-r - r-- 1 группа владельцев 11832668 13 февраля 2015 г. somename.csv-rw-r - r-- 1 группа владельцев 1510522 19 февраля 2015 г. somename.csv-rw-r - r - 1 группа владельцев 2826664 25 февраля 2015 г. somename.csv-rw-r - r-- 1 группа владельцев 582985 26 февраля 2015 г. somename.csv-rw-r - r-- 1 группа владельцев 212427 26 февраля 2015 г. somename.csv -rw-r-r-- 1 группа владельцев 3015592 27 февраля 2015 somen ame.csv-RW-р - r-- 1 владелец группа 103576 27 февраля 2015 SomeName-corrected.csv»

Я пробовал различные воплощения следующего

from re import compile 
ftp_list_re = compile('(?P<permissions>[d-][rwx-]{9})[\s]{1,20}' 
         '(?P<links>[0-9]{1,8})[\s]{1,20}' 
         '(?P<owner>[0-9A-Za-z_-]{1,16})[\s]{1,20}' 
         '(?P<group>[0-9A-Za-z_-]{1,16})[\s]{1,20}' 
         '(?P<size>[0-9]{1,16})[\s]{1,20}' 
         '(?P<month>[A-Za-z]{0,3})[\s]{1,20}' 
         '(?P<date>[0-9]{1,2})[\s]{1,20}' 
         '(?P<timeyear>[0-9:]{4,5})[\s]{1,20}' 
         '(?P<filename>[\s\w\.\-]+)(?=[drwx\-]{10})') 

с последней строкой, как

'(?P<filename>.+)(?=[drwx\-]{10})') 

'(?P<filename>.+(?=[drwx\-]{10}))') 

и первоначально,

'(?P<filename>[\s\w\.\-]+(?=[drwx\-]{10}|$))') 

так я могу захватить последнюю запись

но независимо от того, я получаю следующий вывод

ftp_list_re.findall(test) 

[('-rw-r--r--', 
    '1', 
    'owner', 
    'group', 
    '75148624', 
    'Jan', 
    '6', 
    '2015', 
    'somename.csv-rw-r--r-- 1 owner group  223259072 Feb 26 2015  somename.csv-rw-r--r-- 1 owner group   4041411 Jun 5 2015 somename-adjusted.csv-rw-r--r-- 1 owner group   2879228 May 13 2015 somename.csv-rw-r--r-- 1 owner group  11832668 Feb 13 2015 somename.csv-rw-r--r-- 1 owner group   1510522 Feb 19 2015 somename.csv-rw-r--r-- 1 owner group   2826664 Feb 25 2015 somename.csv-rw-r--r-- 1 owner group   582985 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   212427 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   3015592 Feb 27 2015 somename.csv')] 

Что я делаю неправильно?

+0

я бы подумал, что не спасаясь от дефиса будет проблемой, но это не так. В любом случае, я пробовал его с помощью «\» – artdv

ответ

2

Вы должны сделать суб-шаблон перед опережением нежадного. Далее ваше регулярное выражение может быть сокращен немного так:

(?P<permissions>[d-][rwx-]{9})\s{1,20}(?P<links>\d{1,8})\s{1,20}(?P<owner>[\w-]{1,16})\s{1,20}(?P<group>[\w-]{1,16})\s{1,20}(?P<size>\d{1,16})\s{1,20}(?P<month>[A-Za-z]{0,3})\s{1,20}(?P<date>\d{1,2})\s{1,20}(?P<timeyear>[\d:]{4,5})\s{1,20}(?P<filename>[\s\w.-]+?)(?=[drwx-]{10}|$) 

Или с помощью compile:

from re import compile 

ftp_list_re = compile('(?P<permissions>[d-][rwx-]{9})\s{1,20}' 
    '(?P<links>\d{1,8})\s{1,20}' 
    '(?P<owner>[\w-]{1,16})\s{1,20}' 
    '(?P<group>[\w-]{1,16})\s{1,20}' 
    '(?P<size>\d{1,16})\s{1,20}' 
    '(?P<month>[A-Za-z]{0,3})\s{1,20}' 
    '(?P<date>\d{1,2})\s{1,20}' 
    '(?P<timeyear>[\d:]{4,5})\s{1,20}' 
    '(?P<filename>[\s\w.-]+?)(?=[drwx-]{10}|$)') 

RegEx Demo

Код:

import re 
p = re.compile(ur'(?P<permissions>[d-][rwx-]{9})\s{1,20}(?P<links>\d{1,8})\s{1,20}(?P<owner>[\w-]{1,16})\s{1,20}(?P<group>[\w-]{1,16})\s{1,20}(?P<size>[0-9]{1,16})\s{1,20}(?P<month>[A-Za-z]{0,3})\s{1,20}(?P<date>[0-9]{1,2})\s{1,20}(?P<timeyear>[\d:]{4,5})\s{1,20}(?P<filename>[\s\w.-]+?)(?=[drwx-]{10}|$)') 
test_str = u"-rw-r--r-- 1 owner group  75148624 Jan 6 2015 somename.csv-rw-r--r-- 1 owner group  223259072 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   4041411 Jun 5 2015 somename-adjusted.csv-rw-r--r-- 1 owner group   2879228 May 13 2015 somename.csv-rw-r--r-- 1 owner group  11832668 Feb 13 2015 somename.csv-rw-r--r-- 1 owner group   1510522 Feb 19 2015 somename.csv-rw-r--r-- 1 owner group   2826664 Feb 25 2015 somename.csv-rw-r--r-- 1 owner group   582985 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   212427 Feb 26 2015 somename.csv-rw-r--r-- 1 owner group   3015592 Feb 27 2015 somename.csv-rw-r--r-- 1 owner group   103576 Feb 27 2015 somename-corrected.csv" 

re.findall(p, test_str) 
+1

Я не понимал, что требуются две вопросительные знаки. Предполагалось, что взгляд не подразумевается - жадный. Конечно, дожил до «пословицы». Спасибо, кучка, ты спас меня. – artdv

0

Исправлена ​​ваша последняя строка, группа имен файлов не работала. См фиксированного регулярного выражения и демонстрационный:

(?P<permissions>[d-][rwx-]{9})[\s]{1,20} 
         (?P<links>[0-9]{1,8})[\s]{1,20} 
         (?P<owner>[0-9A-Za-z_-]{1,16})[\s]{1,20} 
         (?P<group>[0-9A-Za-z_-]{1,16})[\s]{1,20} 
         (?P<size>[0-9]{1,16})[\s]{1,20} 
         (?P<month>[A-Za-z]{0,3})[\s]{1,20} 
         (?P<date>[0-9]{1,2})[\s]{1,20} 
         (?P<timeyear>[0-9:]{4,5})[\s]{1,20} 
         (?P<filename>[\w\-]+.\w+) 

Demo here:

+1

Спасибо за помощь, но это недостаточно для имен файлов, содержащих несколько дефис, периодов или без периодов (в случае каталога с именем 2014; который, оказывается, находится в моем фактическом листинге, который, к сожалению, я не могу опубликовать из-за проблем с конфиденциальностью). – artdv

+0

Имена файлов «some-file-name-like-this.extension» не так ли? – ferit

+0

В ссылке, которую вы опубликовали, будет возвращен только «some-file». «-name-like-this.extension» было бы проигнорировано. Но, кроме того, я, конечно, использовал источники, в которых либо нет расширения, либо существует несколько периодов в файле (например, README или blah.tar.gz). – artdv

2

регулярных выражений кванторы по по умолчанию "жадность y ", что означает, что они будут« есть »как можно больше.

[\s\w\.\-]+ 

означает найти, по крайней мере, один и как можно больше пробелов, слова, точки, тире или символов. Взгляд вперед препятствует тому, чтобы он съел весь вход (на самом деле механизм регулярных выражений будет потреблять весь вход, а затем при необходимости отталкиваться), а это означает, что он ест каждую строку спецификации файла, за исключением последней (которая, по мнению смотрящего, должна оставим).

Добавление a? после квантификатора (* ?, +?, ?? и т. д.) делает квантификатор «ленивым» или «неохотным». Это изменяет значение «+» от «совпадения как минимум одного и максимально возможного», чтобы «совместить хотя бы один и не более чем необходимый».

Поэтому изменение этого последнего + на +? должен исправить вашу проблему.

Проблема была не в том, чтобы смотреть вперед, что работает отлично, но с последним подвыражением перед ним.

EDIT:

Даже с этим изменением, регулярное выражение будет не разобрать, что спецификации последней строки файла. Это связано с тем, что регулярные выражения INSISTS должны иметь спецификацию разрешения после имени файла. Чтобы исправить это, мы должны допустить, чтобы этот прогноз не соответствовал (но требует, чтобы он соответствовал всем, а последним спецификациям). Заставить следующие изменения зафиксируют, что

ftp_list_re = compile('(?P<permissions>[d-][rwx-]{9})[\s]{1,20}' 
         '(?P<links>[0-9]{1,8})[\s]{1,20}' 
         '(?P<owner>[0-9A-Za-z_-]{1,16})[\s]{1,20}' 
         '(?P<group>[0-9A-Za-z_-]{1,16})[\s]{1,20}' 
         '(?P<size>[0-9]{1,16})[\s]{1,20}' 
         '(?P<month>[A-Za-z]{0,3})[\s]{1,20}' 
         '(?P<date>[0-9]{1,2})[\s]{1,20}' 
         '(?P<timeyear>[0-9:]{4,5})[\s]{1,20}' 
         '(?P<filename>[\s\w\.\-]+?)(?=(?:(?:[drwx\-]{10})|$))') 

То, что я сделал здесь (кроме того, что делает, что последний + отложенный), чтобы сделать чек опережения две возможности - либо спецификации разрешения или конец строки. «?» - это предотвращение захвата этих скобок (в противном случае в ваших матчах вы получите нежелательные дополнительные данные).

0

С PyPi regex module, что позволяет разделить с пустым матчем, вы можете сделать то же самое в более простой форме, без необходимости описывать все поля:

import regex 

fields = ('permissions', 'links', 'owner', 'group', 'size', 'month', 'day', 'year', 'filename') 
p = regex.compile(r'(?=[d-](?:[r-][w-][x-]){3})', regex.V1) 
res = [dict(zip(fields, x.split(None, 9))) for x in p.split(test)[1:]] 
Смежные вопросы