2

请看看我的心碎。

我坚持使用正则表达式缩小一些漫长的路径,如下所示:

/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890

我想将此路径转换为以下形式:

/123/123/123/123/12/1/123/123/123/123

路径中的每个“目录”仅缩写为前 3 个字符

LONG_PATH="/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890"
perl -pe "s#/(.{1,3})[^/]*?(/|$)#/\1\2#g" <<<$LONG_PATH

/123/123456/123/123/12//1234567/132/123456789/123

sed -E "s#/(.{1,3})[^/]*?(/|$)#/\1\2#g" <<<$LONG_PATH

/123/123456/123/123/12//1234567/132/123456789/123

我也试过:

perl -pe "s,/(.)(.)?(.)?[^/]*+,/\1\2\3,g" <<<$LONG_PATH
/123/123/123/123/12//123/132/123/123

还有很多其他的,没有“运气”——我仍然不知道。

请为我指出一条通往成功的正确道路。

4

3 回答 3

7

最多匹配三个非斜线字符并捕获它们。然后匹配其余的直到下一个斜线。替换为捕获:

"s#(/[^/]{3})[^/]*#\1#g"

/这里不需要不贪心或任何东西,因为否定字符类与or是互斥的$

编辑:虽然您似乎知道这一点,但我可能应该向未来的访问者澄清,这将适用于您在问题中使用过的perl -pe...任何一个。sed -E...正则表达式也可以与sed -r.... 如果您省略-Eor-r选项,那么(像往常一样)您将需要同时转义括号和大括号:

sed "s#\(/[^/]\{3\}\)[^/]*#\1#g" filename

另请注意,ikegami 指出,在 Perl 中,您应该$1在替换中使用而不是\1.

于 2012-11-11T20:12:00.420 回答
3

你可以这样做:

perl -pe's#[^/]{3}\K[^/]*##g'
/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890
/123/123/123/123/12/1/123/132/123/123

找到 3 个非斜线,并保留 ( \K) 它们,删除以下字符直到下一个斜线。

正如 ikegami 所指出的,不需要匹配少于三个字符,在这种情况下,可以使用后向断言代替\K. 好处是\K需要 perl v5.10,而且我相信环视断言早于此。

perl -pe 's#(?<=[^/]{3})[^/]*##g'
于 2012-11-11T20:42:18.140 回答
0

最好的方法似乎是使用File::Spec模块来拆分和重组路径。中间调用map将减少每个路径段的前三个字符。这个程序演示

use strict;
use warnings;

use File::Spec;

my $path = '/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890';

my $newpath = File::Spec->catdir(map substr($_, 0, 3), File::Spec->splitdir($path));

print $newpath;

输出

/123/123/123/123/12/1/123/132/123/123
于 2012-11-12T18:22:49.503 回答