用于解析目录和文件名的正则表达式

Mik*_*eck 26 regex parsing

我正在尝试编写一个正则表达式,它将使用匹配组解析完全限定路径的目录和文件名.

所以...

/var/log/xyz/10032008.log
Run Code Online (Sandbox Code Playgroud)

将承认group 1 to be "/var/log/xyz"group 2 to be "10032008.log"

看似简单,但我不能让匹配的团队为我的生活工作.

注意:正如一些受访者所指出的,这可能不是正常表达的好用.通常我更喜欢使用我正在使用的语言的文件API.我实际上要做的事情比这复杂得多,但要解释起来要困难得多,所以我选择了一个每个人都熟悉的域名,以便最简洁地描述根本问题.

Jer*_*ten 29

试试这个:

^(.+)/([^/]+)$
Run Code Online (Sandbox Code Playgroud)

  • 这假设有一个路径,而不仅仅是一个文件名. (5认同)
  • 它还遇到当前目录(.)和根目录(/)的问题.前者不是问题(完全限定的路径名​​不是以点开头); 后者可能是.正则表达式也不处理..反向遍历 - 这可能没问题,因为完全限定可能意味着没有点点位. (4认同)
  • `^(.+)\ /([^\/ + +)$`正斜杠必须被转义? (4认同)

Cha*_*uis 18

在支持具有非捕获组的正则表达式的语言中:

((?:[^/]*/)*)(.*)
Run Code Online (Sandbox Code Playgroud)

我将通过爆炸来解释这个粗糙的正则表达式......

(
  (?:
    [^/]*
    /
  )
  *
)
(.*)
Run Code Online (Sandbox Code Playgroud)

这些部分意味着什么:

(  -- 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
Run Code Online (Sandbox Code Playgroud)

为了测试正则表达式,我使用了以下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');
Run Code Online (Sandbox Code Playgroud)

脚本的输出......

/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
Run Code Online (Sandbox Code Playgroud)


Tra*_*lig 8

大多数语言都有路径解析功能,可以为您提供此功能.如果你有这种能力,我建议你免费使用免费提供给你的东西.

假设/是路径分隔符...

^(.*/)([^/]*)$
Run Code Online (Sandbox Code Playgroud)

第一组将是目录/路径信息,第二组将是文件名.例如:

  • /foo/bar/baz.log:"/ foo/bar /"是路径,"baz.log"是文件
  • foo/bar.log:"foo /"是路径,"bar.log"是文件
  • / foo/bar:"/ foo /"是路径,"bar"是文件
  • / foo/bar /:"/ foo/bar /"是路径,没有文件.


the*_*der 6

推理:

我通过试错法做了一些研究。发现键盘中可用的所有值都可以是 *nux 机器中除“/”之外的文件或目录。

我使用 touch 命令为以下字符创建文件,它创建了一个文件。

(下面的逗号分隔值)
'!', '@', '#', '$', "'", '%', '^', '&', '*', '(', ')', ' '、'"'、'\'、'-'、','、'['、']'、'{'、'}'、'`'、'~'、'>'、'<' , '=', '+', ';', ':', '|'

仅当我尝试创建“/”(因为它是根目录)和文件名容器/(因为它是文件分隔符)时,它才失败。

.当我这样做时,它改变了当前目录的修改时间touch .。但是,file.log 是可能的。

当然,a-zA-Z0-9-(连字符)、_(下划线)应该可以。

结果

因此,通过上述推理我们知道文件名或目录名可以包含除/正斜杠之外的任何内容。因此,我们的正则表达式将根据文件名/目录名中不存在的内容派生。

/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/
Run Code Online (Sandbox Code Playgroud)

逐步正则表达式创建过程

模式解释

步骤 1:从匹配的root目录开始

/当目录是绝对路径时,目录可以以目录名开头;当目录是相对路径时,目录可以以目录名开头。因此,请查找/出现零次或一次的情况。

/(?P<filepath>(?P<root>[/]?)(?P<rest_of_the_path>.+))/
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

步骤2:尝试找到第一个目录。

接下来,目录及其子目录始终以 分隔/。目录名称可以是除 之外的任何名称/。那么我们先匹配/var/。

/(?P<filepath>(?P<first_directory>(?P<root>[/]?)[^\/]+/)(?P<rest_of_the_path>.+))/
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

步骤 3:获取文件的完整目录路径

接下来,我们来匹配所有目录

/(?P<filepath>(?P<dir>(?P<root>[/]?)(?P<single_dir>[^\/]+/)+)(?P<rest_of_the_path>.+))/
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这里,single_dir是yz/因为,首先它匹配var/,然后它找到下一个出现的相同模式,即log/,然后它找到下一个出现的相同模式yz/。因此,它显示了模式的最后一次出现。

步骤 4:匹配文件名并清理

现在,我们知道我们永远不会使用像 single_dir、filepath、root 这样的组。因此,让我们清理一下。

让我们将它们保留为组,但不要捕获这些组。

而rest_of_the_path 只是文件名!所以,重命名它。并且文件的/名称中不会有,所以最好保留[^/]

/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/
Run Code Online (Sandbox Code Playgroud)

这给我们带来了最终结果。当然,还有其他几种方法可以做到这一点。我在这里只是提到其中一种方法。

在此输入图像描述

此处列出了上面使用的正则表达式规则

^表示字符串以
(?P<dir>pattern)表示按组名称捕获组开头。我们有两个带有组名称的组dir,并且file
(?:pattern)意味着不考虑该组或非捕获组。
?表示匹配零或一。 +表示匹配一个或多个 [^\/]表示匹配除正斜杠 (/ )之外的任何字符

[/]?意味着如果它是绝对路径,那么它可以以 / 开头,否则不会。因此,匹配零次或一次出现的/.

[^\/]+/表示不是正斜杠 ( /) 且后跟正斜杠 ( /) 的一个或多个字符。这将匹配var/xyz/。一次一个目录。


tzo*_*zot 5

什么语言?为什么使用正则表达式来完成这个简单的任务?

如果您必须

^(.*)/([^/]*)$
Run Code Online (Sandbox Code Playgroud)

给你你想要的两个部分。您可能需要引用括号:

^\(.*\)/\([^/]*\)$
Run Code Online (Sandbox Code Playgroud)

取决于您的首选语言语法。

但我建议您只使用您的语言的字符串搜索功能来查找最后一个“/”字符,并在该索引上拆分字符串。