regex 正则表达式匹配除文件及其父目录之外的路径

a9wyjsp7  于 2023-11-20  发布在  其他
关注(0)|答案(5)|浏览(96)

我正在尝试编写一个表达式,它匹配一个文件路径,但不包括文件名及其父目录。这是我的测试字符串:

file/in/some/dir1/file1.txt
file/in/some/dir2/file1.txt
file/in/some/dir2/file2.txt
file/in/some/other/dir/file1.txt

字符串
我想要正则表达式匹配的是:

file/in/some
file/in/some
file/in/some
file/in/some/other


我尝试了不同类型的消极前瞻,但我没有成功。我所能想到的是一个表达式,它与我想要的匹配完全相反:(\w+\/\w+\.\w+)。通过这个表达式,我得到了文件名和它的父目录,但我不知道如何“反转”结果。

a8jjtwal

a8jjtwal1#

你非常接近你的“matches the exact opposite”正则表达式,你只需要捕获字符串的 other 部分:

m{(.*)/\w+/\w+\.\w+$}

字符串
我还修改了它,使匹配的非捕获部分必须以/开头(否则它会给出错误的结果),使用m{}而不是//来分隔正则表达式,这样正则表达式中的/字符就不需要转义了(\/-“倾斜牙签综合症”),并将其锚定到字符串的末尾(这样,如果其中一个目录名包含.,它仍然可以正常工作)。
完整测试实施:

#!/usr/bin/env perl    

use strict;
use warnings;
use 5.010;

my @paths = qw(
  file/in/some/dir1/file1.txt
  file/in/some/dir2/file1.txt
  file/in/some/dir2/file2.txt
  file/in/some/other/dir/file1.txt
);

for my $path (@paths) {
  $path =~ m{(.*)/\w+/\w+\.\w+$};
  say $1;
}


输出量:

file/in/some
file/in/some
file/in/some
file/in/some/other

rkue9o1l

rkue9o1l2#

文件名或目录名不能包含斜杠,所以路径的最后两部分是/[^/]+/[^/]+$

#!/usr/bin/perl
use warnings;
use strict;

use Test::More tests => 4;

my %test = (
    'file/in/some/dir1/file1.txt'      => 'file/in/some',
    'file/in/some/dir2/file1.txt'      => 'file/in/some',
    'file/in/some/dir2/file2.txt'      => 'file/in/some',
    'file/in/some/other/dir/file1.txt' => 'file/in/some/other');

for my $path (keys %test) {
    is match($path), $test{$path}, $path;
}

sub match {
    my ($path) = @_;
    return ($path =~ m{(.*)/[^/]+/[^/]+$})[0]
}

字符串

0ve6wy6x

0ve6wy6x3#

这里有一个方法来做这项工作:

use strict;
use warnings;
use feature 'say';

while(<DATA>) {
    chomp;
    s~/[^/]+/[^/]+$~~;
    say;
}

__DATA__
file/in/some/dir1/file1.txt
file/in/some/dir2/file1.txt
file/in/some/dir2/file2.txt
file/in/some/other/dir/file1.txt

字符串

输出:

file/in/some
file/in/some
file/in/some
file/in/some/other

ckx4rj1h

ckx4rj1h4#

使用这个正则表达式,只有一个参数,可以改变你想要得到的上面的目录数量。改变“{x,}"里面的值,数字越大,你得到的目录越多。

/(.*)(?:(?:\/[^/]+){2,})/g

字符串
因此,使用上面的正则表达式,执行替换并使用group 1(如$1或\1)。结果如下:

file/in/some/dir1
file/in/some/dir2
file/in/some/dir2
file/in/some/other


您可以在shell中使用如下命令(注意,非捕获组“?:“在shell中不起作用):

$ realpath /etc/alternatives/java
$ /usr/lib/jvm/java-18-openjdk-amd64/bin/java

$ realpath /etc/alternatives/java | sed -E 's/(.*)((\/[^/]+){2,})/\1/g'
$ /usr/lib/jvm/java-18-openjdk-amd64


这可以在.bashrc中使用,例如定义JAVA_HOME路径,而不需要确切指定包版本。

export JAVA_HOME="$(realpath /etc/alternatives/java | sed -E 's/(.*)((\/[^/]+){2,})/\1/g')"

qojgxg4l

qojgxg4l5#

下面是另一种方法,假设所有数据都在字符串中,并使用lookahead regexp:

my $files = "1: file/in/some/dir1/file1.txt
2: file/in/some/dir2/file1.txt
3: file/in/some/dir2/file2.txt
4: file/in/some/other/dir/file1.txt";
my @dirs = $files =~ m{((?:\w+/)+)(?=\w+\/\w+\.\w+)}g;
say for @dirs;

字符串

输出

file/in/some/
file/in/some/
file/in/some/
file/in/some/other/

相关问题