我正在尝试编写一个正则表达式,它将使用匹配组解析完全限定路径的目录和文件名.
所以...
/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)
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)
大多数语言都有路径解析功能,可以为您提供此功能.如果你有这种能力,我建议你免费使用免费提供给你的东西.
假设/是路径分隔符...
^(.*/)([^/]*)$
Run Code Online (Sandbox Code Playgroud)
第一组将是目录/路径信息,第二组将是文件名.例如:
我通过试错法做了一些研究。发现键盘中可用的所有值都可以是 *nux 机器中除“/”之外的文件或目录。
我使用 touch 命令为以下字符创建文件,它创建了一个文件。
(下面的逗号分隔值)
'!', '@', '#', '$', "'", '%', '^', '&', '*', '(', ')', ' '、'"'、'\'、'-'、','、'['、']'、'{'、'}'、'`'、'~'、'>'、'<' , '=', '+', ';', ':', '|'
仅当我尝试创建“/”(因为它是根目录)和文件名容器/(因为它是文件分隔符)时,它才失败。
.当我这样做时,它改变了当前目录的修改时间touch .。但是,file.log 是可能的。
当然,a-z、A-Z、0-9、-(连字符)、_(下划线)应该可以。
因此,通过上述推理我们知道文件名或目录名可以包含除/正斜杠之外的任何内容。因此,我们的正则表达式将根据文件名/目录名中不存在的内容派生。
/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/
Run Code Online (Sandbox Code Playgroud)
root目录开始/当目录是绝对路径时,目录可以以目录名开头;当目录是相对路径时,目录可以以目录名开头。因此,请查找/出现零次或一次的情况。
/(?P<filepath>(?P<root>[/]?)(?P<rest_of_the_path>.+))/
Run Code Online (Sandbox Code Playgroud)
接下来,目录及其子目录始终以 分隔/。目录名称可以是除 之外的任何名称/。那么我们先匹配/var/。
/(?P<filepath>(?P<first_directory>(?P<root>[/]?)[^\/]+/)(?P<rest_of_the_path>.+))/
Run Code Online (Sandbox Code Playgroud)
接下来,我们来匹配所有目录
/(?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/。因此,它显示了模式的最后一次出现。
现在,我们知道我们永远不会使用像 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/。一次一个目录。
什么语言?为什么使用正则表达式来完成这个简单的任务?
如果您必须:
^(.*)/([^/]*)$
Run Code Online (Sandbox Code Playgroud)
给你你想要的两个部分。您可能需要引用括号:
^\(.*\)/\([^/]*\)$
Run Code Online (Sandbox Code Playgroud)
取决于您的首选语言语法。
但我建议您只使用您的语言的字符串搜索功能来查找最后一个“/”字符,并在该索引上拆分字符串。