Я пытаюсь написать регулярное выражение, которое будет анализировать каталог и имя файла полного пути, используя соответствующие группы.
так...
/var/log/xyz/10032008.log
распознал бы group 1 to be "/var/log/xyz" и group 2 to be "10032008.log"
Кажется простым, но я не могу заставить соответствующие группы работать на всю жизнь.
ПРИМЕЧАНИЕ. Как указали некоторые респонденты, это, вероятно, не очень хорошее использование регулярных выражений. Как правило, я бы предпочел использовать файловый API языка, который я использовал. То, что я на самом деле пытаюсь сделать, немного сложнее, чем это, но было бы гораздо труднее объяснить, поэтому я выбрал область, с которой все были бы знакомы, чтобы наиболее кратко описать основную проблему.





Какой язык? и зачем использовать регулярное выражение для этой простой задачи?
Если вы должен:
^(.*)/([^/]*)$
дает вам две части, которые вы хотели. Возможно, вам потребуется указать скобки:
^\(.*\)/\([^/]*\)$
в зависимости от синтаксиса предпочитаемого вами языка.
Но я предлагаю вам просто использовать функцию поиска строки вашего языка, которая находит последний символ «/», и разбивать строку по этому индексу.
Да, но он еще не указал язык. Если бы это был Python, я бы предложил os.path.dirname и os.path.basename.
Попробуй это:
^(.+)/([^/]+)$
Обновлено: экранировал косую черту, чтобы предотвратить проблемы при копировании / вставке регулярного выражения
Разве вы не хотите сделать это не жадным (если это анонимное регулярное выражение может с этим справиться), чтобы ему не приходилось возвращаться полностью до косой черты?
Предполагается, что существует путь, а не только имя файла.
Также возникают проблемы с текущим каталогом (.) И корневым каталогом (/). Первое не является проблемой (полные имена путей не начинаются с точки); последнее могло бы быть. Регулярное выражение также не обрабатывает ... обратный обход - это может быть нормально, потому что полное определение может означать отсутствие битов точка-точка.
Это также работает ... r '. * / (. *) $', Группа 0 вернет имя файла. Поскольку. * По умолчанию является жадным, он выполняет всю работу. Снова предполагает, что есть путь.
^(.+)/([^/]+)$ Косые черты должны быть экранированы?
Вам нужно избегать косых черт, но в противном случае этот ответ был именно тем, что мне нужно, когда я пытался решить этот вопрос на Answers.Splunk.com - answers.splunk.com/answers/777810/…
Попробуй это:
/^(/([^/]+/)*)(.*)$/
Однако при этом на пути останется косая черта.
В большинстве языков есть функции синтаксического анализа пути, которые уже дадут вам это. Если у вас есть возможность, я бы порекомендовал использовать то, что приходит к вам бесплатно, прямо из коробки.
Предполагая, что / является разделителем пути ...
^(.*/)([^/]*)$
Первая группа будет содержать информацию о каталоге / пути, вторая - имя файла. Например:
Как насчет этого?
[/]{0,1}([^/]+[/])*([^/]*)
Детерминированный:
((/)|())([^/]+/)*([^/]*)
Строгий :
^[/]{0,1}([^/]+[/])*([^/]*)$
^((/)|())([^/]+/)*([^/]*)$
Очень поздний ответ, но надеюсь, что это поможет
^(.+?)/([\w]+\.log)$
Здесь используется ленивая проверка для /, и я только что изменил принятый ответ.
В языках, поддерживающих регулярные выражения с не захватывающие группы:
((?:[^/]*/)*)(.*)
Я объясню грубое регулярное выражение, взорвав его ...
(
(?:
[^/]*
/
)
*
)
(.*)
Что означают части:
( -- 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: \n";
print " 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
Я провел небольшое исследование методом проб и ошибок. Выяснилось, что все значения, доступные на клавиатуре, могут быть файлом или каталогом, за исключением '/' на машине * nux.
Я использовал команду touch для создания файла для следующих символов, и он создал файл.
(Comma separated values below)
'!', '@', '#', '$', "'", '%', '^', '&', '*', '(', ')', ' ', '"', '\', '-', ',', '[', ']', '{', '}', '`', '~', '>', '<', '=', '+', ';', ':', '|'
Это не удалось только тогда, когда я попытался создать '/' (потому что это корневой каталог) и контейнер имени файла /, потому что это разделитель файлов.
И это изменило время изменения текущего каталога ., когда я сделал touch .. Однако file.log возможен.
И, конечно же, a-z, A-Z, 0-9, - (hypen), _ (подчеркивание) должны работать.
Итак, из приведенных выше рассуждений мы знаем, что имя файла или имя каталога может содержать что угодно, кроме прямой косой черты /. Итак, наше регулярное выражение будет производным от того, чего не будет в имени файла / имени каталога.
/(?:(?P<dir>(?:[/]?)(?:[^/]+/)+)(?P<filename>[^/]+))/
root.Каталог может начинаться с /, если это абсолютный путь, и имя каталога, если оно относительное. Следовательно, ищите / с одним или одним экземпляром.
/(?P<filepath>(?P<root>[/]?)(?P<rest_of_the_path>.+))/
Далее, каталог и его дочерний элемент всегда разделяются /. И имя каталога может быть любым, кроме /. Тогда давайте сначала сопоставим / var /.
/(?P<filepath>(?P<first_directory>(?P<root>[/]?)[^/]+/)(?P<rest_of_the_path>.+))/
Далее сопоставим все каталоги
/(?P<filepath>(?P<dir>(?P<root>[/]?)(?P<single_dir>[^/]+/)+)(?P<rest_of_the_path>.+))/
Здесь single_dir - это yz/, потому что сначала он соответствовал var/, затем он нашел следующее вхождение того же шаблона, то есть log/, затем он нашел следующее вхождение того же шаблона yz/. Итак, он показал последнее появление паттерна.
Теперь мы знаем, что никогда не будем использовать такие группы, как single_dir, filepath, root. Поэтому давайте уберем это.
Давайте оставим их группами, но не захватываем эти группы.
И rest_of_the_path - это просто имя файла! Итак, переименуйте его. И в имени файла не будет /, поэтому лучше оставить [^/].
/(?:(?P<dir>(?:[/]?)(?:[^/]+/)+)(?P<filename>[^/]+))/
Это подводит нас к окончательному результату. Конечно, есть несколько других способов сделать это. Я просто упоминаю здесь один из способов.
^ означает, что строка начинается с (?P<dir>pattern) означает группу захвата по имени группы. У нас есть две группы с названием группы dir и file
.
(?:pattern) означает не рассматривать эту группу или группу без захвата.
? означает соответствие нулю или единице.
+ означает соответствие одному или нескольким
[^/] означает соответствие любому символу, кроме косой черты (/)
[/]? означает, что если это абсолютный путь, он может начинаться с / в противном случае - нет. Итак, сопоставьте ноль или одно вхождение /.
[^/]+/ означает один или несколько символов, не являющихся косой чертой (/), за которой следует косая черта (/). Это будет соответствовать var/ или xyz/. По одному каталогу за раз.
имя файла / каталога в большинстве (если не во всех) файловых системах, созданных в среде * nix, принимает все байтовые значения, кроме '/' и '\ 0'.
Многие фреймворки (например, .NET / Python) имеют методы для отделения имен файлов от путей без необходимости вручную искать символ '/'. Это замечательно, потому что инструменты, как правило, не зависят от платформы.