A有一个文件列表,其中一些名称后缀为.cloud。如何编写一个正则表达式来获取没有.cloud部分的文件名?
这是我尝试的perl脚本示例。
#! /usr/bin/perl -w
my @log_files = ('infolog.txt', 'errorlog.txt.cloud', 'dailyerrorlog.txt.cloud', 'trace.output.cloud', 'debug.log.cloud');
foreach my $file (@log_files)
{
print $1."\n" if($file =~ /(.+?)(?:\.cloud)?/);
}
这将打印以下内容:
$ perl test.pl
i
e
d
t
d
如果我摆脱了'?'这使得。+贪婪,它匹配所有东西,包括.cloud。
#! /usr/bin/perl -w
my @log_files = ('infolog.txt', 'errorlog.txt.cloud', 'dailyerrorlog.txt.cloud', 'trace.output.cloud', 'debug.log.cloud');
foreach my $file (@log_files)
{
print $1."\n" if($file =~ /(.+)(?:\.cloud)?/);
}
这将打印以下内容:
$ perl test.pl
infolog.txt
errorlog.txt.cloud
dailyerrorlog.txt.cloud
trace.output.cloud
debug.log.cloud
我真正想要的是一个正则表达式,打印出来:
$ perl test.pl
infolog.txt
errorlog.txt
dailyerrorlog.txt
trace.output
debug.log
我已经将我的真实用例修改为一个非常简单的例子。我需要在这里使用正则表达式来匹配文件名,所以像
这样的答案$file =~ s/\.cloud$//;
print $file."\n";
对我不起作用。
我也在C#中尝试了类似的事情,结果相似。
static void Main(string[] args)
{
Regex regex = new Regex(@"(?<filename>.+?)(?:\.cloud)?");
string text = "abcdef.txt.cloud";
Match match = regex.Match(text);
if(match.Success)
{
Console.WriteLine("Found filename: {0}", match.Groups["filename"].Value);
}
}
// Output
// Found filename: a
感谢您的帮助。
答案 0 :(得分:4)
如果指定整个字符串必须匹配,则通常更容易阅读/维护正则表达式。这对^
和$
很容易,它与字符串的开头和结尾相匹配。
匹配字符串中的任意位置:(.+?)(?:\.cloud)?
匹配整个字符串:^(.+?)(?:\.cloud)?$
在第二种情况下,非贪婪组将尽可能少地捕获,但需要捕获多个字符以满足匹配条件。
这并不涵盖所有可能的用例,但它往往会导致正则表达式在六个月后更容易阅读。
答案 1 :(得分:1)
它只匹配一个字符,因为您告诉它匹配尽可能少的字符数,并且.+
不允许匹配零个字符。
⇒我将使用$PAT
代替.+
,因为你说这是一个更复杂的替代品。
尽管您声称s///
无法使用,但它似乎仍然是我最简单的解决方案。
my ($match) = map { s/\.cloud\z//r } $file =~ /^($PAT)\z/; # 5.14+
或
my ($match) = map { ( my $s = $_ ) =~ s/\.cloud\z//; $s } $file =~ /^($PAT)\z/;
也就是说,也可以使用匹配来实现:
my $match = $file =~ /^(?:($PAT)(?=\.cloud\z)|($PAT))/ ? ($1 // $2) : undef;
顺便说一下,如果$PAT
是.+
,并且我想使用匹配,我会使用以下内容:
my ($match) = $file =~ /^((?:(?!\.cloud\z).)+)/s;
但使用
会更简单my $match = $file =~ s/\.cloud\z//r; # 5.14+
或
(my $match = $file) =~ s/\.cloud\z//;
答案 2 :(得分:0)
您的模式仅匹配单个字符的原因是子模式(?:\.cloud)?
是可选的,因此可以完全满足它。这使得(.+?)
可以自由匹配+
量词所允许的最短字符串,这是一个字符
通过锚定模式的结尾以使其必须匹配整个字符串
,可以轻松解决此问题。此代码可以正常使用
use strict;
use warnings 'all';
my @log_files = qw/
infolog.txt
errorlog.txt.cloud
dailyerrorlog.txt.cloud
trace.output.cloud
debug.log.cloud
/;
for ( @log_files ) {
print "$1\n" if /(.+?)(?:\.cloud)?$/;
}
infolog.txt
errorlog.txt
dailyerrorlog.txt
trace.output
debug.log
答案 3 :(得分:0)
将文件名分配给临时变量并进行修改。
my @log_files = qw(
infolog.txt
errorlog.txt.cloud
dailyerrorlog.txt.cloud
trace.output.cloud
debug.log.cloud
);
foreach my $file (@log_files)
{
my $tmpry = $file;
$tmpry =~ s/\.cloud$//;
printf "%-25s %s\n", $file, $tmpry;
}