Регулярное выражение для анализа каталога и имени файла

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

так...

/var/log/xyz/10032008.log

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
35
0
160 667
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

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

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

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

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

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

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

Многие фреймворки (например, .NET / Python) имеют методы для отделения имен файлов от путей без необходимости вручную искать символ '/'. Это замечательно, потому что инструменты, как правило, не зависят от платформы.

Jordan Parmer 04.10.2008 01:46

Да, но он еще не указал язык. Если бы это был Python, я бы предложил os.path.dirname и os.path.basename.

tzot 04.10.2008 22:47
Ответ принят как подходящий

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

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

Обновлено: экранировал косую черту, чтобы предотвратить проблемы при копировании / вставке регулярного выражения

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

Axeman 04.10.2008 01:52

Предполагается, что существует путь, а не только имя файла.

Travis Illig 04.10.2008 01:59

Также возникают проблемы с текущим каталогом (.) И корневым каталогом (/). Первое не является проблемой (полные имена путей не начинаются с точки); последнее могло бы быть. Регулярное выражение также не обрабатывает ... обратный обход - это может быть нормально, потому что полное определение может означать отсутствие битов точка-точка.

Jonathan Leffler 04.10.2008 02:48

Это также работает ... r '. * / (. *) $', Группа 0 вернет имя файла. Поскольку. * По умолчанию является жадным, он выполняет всю работу. Снова предполагает, что есть путь.

Paul Kenjora 02.12.2017 05:34

^(.+)/([^/]+)$ Косые черты должны быть экранированы?

Neil Agarwal 27.02.2018 22:11

Вам нужно избегать косых черт, но в противном случае этот ответ был именно тем, что мне нужно, когда я пытался решить этот вопрос на Answers.Splunk.com - answers.splunk.com/answers/777810/…

warren 17.10.2019 17:01

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

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

Однако при этом на пути останется косая черта.

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

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

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

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

  • /foo/bar/baz.log: «/ foo / bar /» - это путь, «baz.log» - это файл
  • foo / bar.log: «foo /» - это путь, «bar.log» - это файл
  • / foo / bar: "/ foo /" - это путь, "bar" - это файл
  • / foo / bar /: «/ foo / bar /» - это путь, а файла нет.

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

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

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

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

Строгий :

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

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

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

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

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

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

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

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

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

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

(  -- 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>[^/]+))/

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

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

Шаг 1. Начните с соответствующего каталога root.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Здесь перечислены правила регулярных выражений, использованные выше.

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

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

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

имя файла / каталога в большинстве (если не во всех) файловых системах, созданных в среде * nix, принимает все байтовые значения, кроме '/' и '\ 0'.

tzot 17.06.2020 18:53

Другие вопросы по теме