Regex для разбора каталога и имени файла - PullRequest
25 голосов
/ 04 октября 2008

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

так ...

/var/log/xyz/10032008.log

распознал бы group 1 to be "/var/log/xyz" и group 2 to be "10032008.log"

Кажется простым, но я не могу заставить соответствующие группы работать на всю жизнь.

ПРИМЕЧАНИЕ. Как указали некоторые респонденты, это, вероятно, нецелесообразное использование регулярных выражений. Обычно я предпочитаю использовать файловый API того языка, который я использовал. То, что я на самом деле пытаюсь сделать, немного сложнее, чем это, но было бы гораздо сложнее объяснить, поэтому я выбрал область, с которой все будут знакомы, чтобы наиболее кратко описать корневую проблему.

Ответы [ 8 ]

30 голосов
/ 04 октября 2008

Попробуйте это:

^(.+)/([^/]+)$
16 голосов
/ 08 октября 2015

На языках, которые поддерживают регулярные выражения с не захватывающими группами :

((?:[^/]*/)*)(.*)

Я объясню страшное регулярное выражение, взорвав его ...

(
  (?:
    [^/]*
    /
  )
  *
)
(.*)

Что означают части:

(  -- capture group 1 starts
  (?:  -- non-capturing group starts
    [^/]*  -- greedily match as many non-directory separators as possible
    /  -- match a single directory-separator character
  )  -- non-capturing group ends
  *  -- repeat the non-capturing group zero-or-more times
)  -- capture group 1 ends
(.*)  -- capture all remaining characters in group 2

Пример

Чтобы проверить регулярное выражение, я использовал следующий скрипт Perl ...

#!/usr/bin/perl -w

use strict;
use warnings;

sub test {
  my $str = shift;
  my $testname = shift;

  $str =~ m#((?:[^/]*/)*)(.*)#;

  print "$str -- $testname\n";
  print "  1: $1\n";
  print "  2: $2\n\n";
}

test('/var/log/xyz/10032008.log', 'absolute path');
test('var/log/xyz/10032008.log', 'relative path');
test('10032008.log', 'filename-only');
test('/10032008.log', 'file directly under root');

Вывод скрипта ...

/var/log/xyz/10032008.log -- absolute path
  1: /var/log/xyz/
  2: 10032008.log

var/log/xyz/10032008.log -- relative path
  1: var/log/xyz/
  2: 10032008.log

10032008.log -- filename-only
  1:
  2: 10032008.log

/10032008.log -- file directly under root
  1: /
  2: 10032008.log
8 голосов
/ 04 октября 2008

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

Предполагается / является разделителем пути ...

^(.*/)([^/]*)$

Первой группой будет любая информация о каталоге / пути, вторая будет именем файла. Например:

  • / foo / bar / baz.log : "/ foo / bar /" - это путь, "baz.log" - это файл
  • foo / bar.log : "foo /" - это путь, "bar.log" - это файл
  • / foo / bar : "/ foo /" - это путь, "bar" - это файл
  • / foo / bar / : "/ foo / bar /" - это путь, и файла нет.
4 голосов
/ 04 октября 2008

На каком языке? и зачем использовать регулярные выражения для этой простой задачи?

Если вы должны :

^(.*)/([^/]*)$

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

^\(.*\)/\([^/]*\)$

в зависимости от вашего предпочтительного синтаксиса языка.

Но я предлагаю вам просто использовать функцию поиска строки вашего языка, которая находит последний символ "/", и разделить строку по этому индексу.

1 голос
/ 03 декабря 2011

Как насчет этого?

[/]{0,1}([^/]+[/])*([^/]*)

Детерминированный:

((/)|())([^/]+/)*([^/]*)

Строгий:

^[/]{0,1}([^/]+[/])*([^/]*)$
^((/)|())([^/]+/)*([^/]*)$
0 голосов
/ 09 апреля 2019

Рассуждение:

Я провел небольшое исследование методом проб и ошибок. Выяснилось, что все значения, доступные на клавиатуре, могут быть файлом или каталогом, кроме '/' в * nux machine.

Я использовал команду touch, чтобы создать файл для следующих символов, и он создал файл.

(значения, разделенные запятыми ниже)
'!', '@', '#', '$', "'",'% ',' ^ ',' & ',' * ',' (',') ',' ',' "' , '\', '-', ',', '[', ']', '{', '}', '`', '~', '>', '<', '=', ' + ','; ',': ',' | '</p>

Не удалось, только когда я попытался создать '/' (потому что это корневой каталог) и контейнер имени файла /, потому что это разделитель файлов.

И это изменило время изменения текущего каталога ., когда я сделал touch .. Однако файл file.log возможен.

И, конечно, a-z, A-Z, 0-9, - (hypen), _ (подчеркивание) должны работать.

Результат

Итак, по приведенным выше рассуждениям мы знаем, что имя файла или имя каталога может содержать что угодно, кроме / прямой слеш. Таким образом, наше регулярное выражение будет получено из того, что не будет присутствовать в имени файла / имени каталога.

/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/

Шаг за шагом процесс создания регулярного выражения

Шаблон Объяснение

Шаг 1: начать с сопоставления root directory

Каталог может начинаться с /, когда он является абсолютным путем, и именем каталога, когда он является относительным. Следовательно, ищите / с нулем или одним вхождением.

/(?P<filepath>(?P<root>[/]?)(?P<rest_of_the_path>.+))/

enter image description here

Шаг 2: Попробуйте найти первый каталог.

Затем каталог и его дочерний элемент всегда отделяются /. И имя каталога может быть любым, кроме /. Давайте сначала сопоставим / var /.

/(?P<filepath>(?P<first_directory>(?P<root>[/]?)[^\/]+/)(?P<rest_of_the_path>.+))/

enter image description here

Шаг 3: Получить полный путь к файлу каталога

Далее, давайте сопоставим все каталоги

/(?P<filepath>(?P<dir>(?P<root>[/]?)(?P<single_dir>[^\/]+/)+)(?P<rest_of_the_path>.+))/

enter image description here

Здесь single_dir равен yz/, потому что сначала он соответствовал var/, затем он обнаружил следующее вхождение того же шаблона, то есть log/, затем он обнаружил следующее вхождение того же шаблона yz/. Итак, он показал последнее появление паттерна.

Шаг 4: сопоставить имя файла и очистить

Теперь мы знаем, что никогда не будем использовать такие группы, как single_dir, filepath, root. Поэтому давайте очистим это.

Давайте сохраним их как группы, но не собираем их.

И rest_of_the_path - это просто имя файла! Итак, переименуйте его. И файл не будет иметь / в названии, поэтому лучше оставить [^/]

/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/

Это подводит нас к конечному результату. Конечно, есть несколько других способов сделать это. Я просто упоминаю один из способов здесь.

enter image description here

Правила Regex, использованные выше, перечислены здесь

^ означает, что строка начинается с
(?P<dir>pattern) означает захват группы по имени группы. У нас есть две группы с именем группы dir и file
(?:pattern) означает, что не следует рассматривать эту группу или группу без захвата.
? означает совпадение ноль или единицу. + означает совпадение с одним или несколькими [^\/] означает, что соответствует любому символу, кроме косой черты (/)

[/]? означает, что если это абсолютный путь, то он может начинаться с / в противном случае он не будет. Итак, сопоставьте ноль или одно вхождение /.

[^\/]+/ означает один или несколько символов, которые не являются косой чертой (/), за которой следует косая черта (/). Это будет соответствовать var/ или xyz/. Один каталог за раз.

0 голосов
/ 29 октября 2014

Очень поздний ответ, но надеюсь, что это поможет

^(.+?)/([\w]+\.log)$

Используется ленивая проверка для /, и я только что изменил принятый ответ

http://regex101.com/r/gV2xB7/1

0 голосов
/ 04 октября 2008

Попробуйте это:

/^(\/([^/]+\/)*)(.*)$/

Это оставит косую черту на пути, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...