2008-11-05 2 views
0

Как я могу создать регулярное выражение для строки, такие как это:Как обрабатывать строку, например, с помощью регулярных выражений?

<SERVER> <SERVERKEY> <COMMAND> <FOLDERPATH> <RETENTION> <TRANSFERMODE> <OUTPUTPATH> <LOGTO> <OPTIONAL-MAXSIZE> <OPTIONAL-OFFSET> 

Большинство из этих полей только простые слова, но некоторые из них могут быть пути, такие как путь_к_папке, OutputPath, эти пути могут быть также пути с именем файла и подстановочным знаком.

Сохранение - это номер, а режим передачи может быть бином или ascii. Проблема заключается в том, что LOGTO может быть путём с именем файла журнала, добавленным к нему, или может быть НЕТ, что означает отсутствие файла журнала.

Основная проблема, это необязательные аргументы, они оба числа, а OFFSET не может существовать без MAXSIZE, но MAXSIZE может существовать без смещения.

Heres некоторые примеры:

loveserver love copy /muffin* 20 bin C:\Puppies\ NO 256 300 
loveserver love copy /muffin* 20 bin C:\Puppies\ NO 256 
loveserver love copy /hats* 300 ascii C:\Puppies\no\ C:\log\love.log 256 

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

Также, если я в конечном итоге использую. и начните удалять его части, регулярное выражение начнет помещать вещи туда, где это не должно.

Heres мое регулярное выражение:

^(\s+)?(?P<SRCHOST>.+)(\s+)(?P<SRCKEY>.+)(\s+)(?P<COMMAND>COPY)(\s+)(?P<SRCDIR>.+)(\s+)(?P<RETENTION>\d+)(\s+)(?P<TRANSFER_MODE>BIN|ASC|BINARY|ASCII)(\s+)(?P<DSTDIR>.+)(\s+)(?P<LOGFILE>.+)(\s+)?(?P<SIZE>\d+)?(\s+)?(?P<OFFSET>\d+)?$ 

ответ

1

Простое разделение на пробелы никогда не сработает. Но если вы можете сделать некоторые предположения о данных, это может быть сделано для работы.

Некоторые предположения я имел в виду:

  • SERVER, SERVERKEY и COMMAND не содержащие каких-либо пространств: \S+
  • FOLDERPATH начиная с косой черты: /.*?
  • RETENTION быть номер: \d+
  • TRANSFERMODE не содержит пробелов: \S+
  • OUTPUTPATH начиная с диска и заканчивая косой чертой: [A-Z]:\\.*?\\
  • LOGTO либо быть слово «NO», или путь, начинающийся с диска: [A-Z]:\\.*?
  • MAXSIZE и OFFSET будучи номер: \d+

Собираем все вместе:

^\s* 
(?P<SERVER>\S+)\s+ 
(?P<SERVERKEY>\S+)\s+ 
(?P<COMMAND>\S+)\s+ 
(?P<FOLDERPATH>/.*?)\s+ # Slash not that important, but should start with non-whitespace 
(?P<RETENTION>\d+)\s+ 
(?P<TRANSFERMODE>\S+)\s+ 
(?P<OUTPUTPATH>[A-Z]:\\.*?\\)\s+ # Could also support network paths 
(?P<LOGTO>NO|[A-Z]:\\.*?) 
(?: 
    \s+(?P<MAXSIZE>\d+) 
    (?: 
    \s+(?P<OFFSET>\d+) 
)? 
)? 
\s*$ 

В одной строке:

^\s*(?P<SERVER>\S+)\s+(?P<SERVERKEY>\S+)\s+(?P<COMMAND>\S+)\s+(?P<FOLDERPATH>/.*?)\s+(?P<RETENTION>\d+)\s+(?P<TRANSFERMODE>\S+)\s+(?P<OUTPUTPATH>[A-Z]:\\.*?\\)\s+(?P<LOGTO>NO|[A-Z]:\\.*?)(?:\s+(?P<MAXSIZE>\d+)(?:\s+(?P<OFFSET>\d+))?)?\s*$ 

Testing:

>>> import re 
>>> p = re.compile(r'^(?P<SERVER>\S+)\s+(?P<SERVERKEY>\S+)\s+(?P<COMMAND>\S+)\s+(?P<FOLDERPATH>/.*?)\s+(?P<RETENTION>\d+)\s+(?P<TRANSFERMODE>\S+)\s+(?P<OUTPUTPATH>[A-Z]:\\.*?\\)\s+(?P<LOGTO>NO|[A-Z]:\\.*?)(?:\s+(?P<MAXSIZE>\d+)(?:\s+(?P<OFFSET>\d+))?)?\s*$',re.M) 
>>> data = r"""loveserver love copy /muffin* 20 bin C:\Puppies\ NO 256 300 
... loveserver love copy /muffin* 20 bin C:\Puppies\ NO 256 
... loveserver love copy /hats* 300 ascii C:\Puppies\no\ C:\log\love.log 256""" 
>>> import pprint 
>>> for match in p.finditer(data): 
... print pprint.pprint(match.groupdict()) 
... 
{'COMMAND': 'copy', 
'FOLDERPATH': '/muffin*', 
'LOGTO': 'NO', 
'MAXSIZE': '256', 
'OFFSET': '300', 
'OUTPUTPATH': 'C:\\Puppies\\', 
'RETENTION': '20', 
'SERVER': 'loveserver', 
'SERVERKEY': 'love', 
'TRANSFERMODE': 'bin'} 
{'COMMAND': 'copy', 
'FOLDERPATH': '/muffin*', 
'LOGTO': 'NO', 
'MAXSIZE': '256', 
'OFFSET': None, 
'OUTPUTPATH': 'C:\\Puppies\\', 
'RETENTION': '20', 
'SERVER': 'loveserver', 
'SERVERKEY': 'love', 
'TRANSFERMODE': 'bin'} 
{'COMMAND': 'copy', 
'FOLDERPATH': '/hats*', 
'LOGTO': 'C:\\log\\love.log', 
'MAXSIZE': '256', 
'OFFSET': None, 
'OUTPUTPATH': 'C:\\Puppies\\no\\', 
'RETENTION': '300', 
'SERVER': 'loveserver', 
'SERVERKEY': 'love', 
'TRANSFERMODE': 'ascii'} 
>>> 
+0

Это было потрясающе. Большое спасибо. – UberJumper

4

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

3

теоретически возможно, но вы делаете вещи невероятно трудными для себя. У вас есть ряд проблем:

1) Вы используете пространство в качестве разделителя, и вы также допускаете пробелы в именах путей. Вы можете избежать этого, заставляя приложение использовать пути без пробелов в них.

2) У вас есть 2 дополнительных параметра на конце. Это означает, что при завершении строки «C: \ LogTo Path 256 300» вы понятия не имеете, является ли путь C: \ LogTo Path 256 300 без дополнительных параметров или C: \ Log To Path 256 с одним необязательным параметром или C: \ LogTo Path с 2 необязательными параметрами.

Это легко будет исправить с помощью алгоритма замены на выходе. Замена пробелов подчеркиванием и подчеркиванием двойным подчеркиванием. Поэтому вы можете полностью отменить это действие после того, как вы разделили файл журнала на пробелы.

Даже в качестве человека вы не могли надежно выполнить эту функцию на 100%.

Если вы предполагаете, что все пути либо заканчиваются звездочкой, либо обратной косой чертой или .log, вы можете использовать позитивный взгляд, чтобы найти конец путей, но без каких-либо правил относительно этого вы набиты.

У меня возникает ощущение, что одно регулярное выражение будет слишком сложно для этого и заставит любого пытаться сохранить код безумным. Я шлюха-реджекс, используя их, когда это возможно, и я бы не попытался это сделать.

0

Вам нужно ограничить поля между путями таким образом, чтобы регулярное выражение могло отличать их от путей.

Так что, если вы положили в специальный сепаратор, последовательность

<OUTPUTPATH> <LOGTO> 

с пробелами или не будет работать.

И если путь может выглядеть как эти поля, вы можете получить неожиданные результаты. , например.

c:\ 12 bin \ 250 bin \output 

для

<FOLDERPATH> <RETENTION> <TRANSFERMODE> <OUTPUTPATH> 

неразличима.

Итак, давайте попробуем ограничить допустимые символы немного:

<SERVER>, <SERVERKEY>, <COMMAND> no spaces -> [^]+ 
<FOLDERPATH> allow anything -> .+ 
<RETENTION> integer -> [0-9]+ 
<TRANSFERMODE> allow only bin and ascii -> (bin|ascii) 
<OUTPUTPATH> allow anything -> .+ 
<LOGTO> allow anything -> .+ 
<OPTIONAL-MAXSIZE>[0-9]* 
<OPTIONAL-OFFSET>[0-9]* 

Итак, я пошел бы с чем-то вдоль линий

[^]+ [^]+ [^]+ .+ [0-9]+ (bin|ascii) .+ \> .+([0-9]* ([0-9]*)?)? 

С «>», чтобы отделить два тракты. Вместо этого вы можете указать пути.

NB: Это было сделано в спешке.

-1

меньше, чем/больше, чем разрешено внутри значений?Потому что, если не у вас есть очень простое решение:

Просто заменить когда-либо вхождение в «>» только с «>», раскол на «> <», и раздеть все меньше/больше, чем от каждого пункта. Вероятно, это длиннее кода регулярного выражения, но будет ясно, что происходит.

+0

<> не используются, чтобы процитировать токены в реальных строках - они просто задаются спецификатором строкового формата. – mackenir

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