简体   繁体   English

如果子模式捕获不匹配,是否有 Perl 正则表达式元字符或指定默认值的方法?

[英]Is there a Perl regex metacharacter or a way to have specify a default value, if a subpattern capture does not match?

Here's the idea.这是想法。 I am parsing command line options but doing it across the entire command line, not by each @ARGV element separately.我正在解析命令行选项,但在整个命令行中进行解析,而不是通过每个 @ARGV 元素单独进行。

program --format="%H:%M:%S" --timeout 12 --nofail

I want the parsing to work with these cases.我希望解析能够处理这些情况。

  1. --name=value , easy to parse --name=value ,易于解析
  2. --name value, pretty easy --name 值,很简单
  3. --name no value , default the value to 1 --name 无值,默认值为 1

Here is the regex which works, except it cannot do the missing value case这是有效的正则表达式,除了它不能做缺失值的情况

%options = "@ARGV" ~= /--([A-Za-z]+)[= ]([^-]\S*)/g;

ie match --name=value or --name value but not --name --name , --name --name is two names, not a --name=value pair.即匹配--name=value--name value但不匹配 --name --name , --name --name 是两个名称,而不是 --name=value 对。

If a --name has no value following it that matches the second capture in the regex, is there a way, within the regex, to specify a default, in my case a 1, to indicate "true".如果--name后面没有与正则表达式中的第二个捕获匹配的值,是否有办法在正则表达式中指定默认值,在我的情况下为 1,以指示“真”。 ie if an --name has no argument, like --nofail then set that argument to 1 indicating true.即,如果 --name 没有参数,例如--nofail ,则将该参数设置为 1,表示为真。

Actually, in asking this I figured out a workaround using separate match statements which is fine.实际上,在问这个问题时,我想出了一个使用单独的匹配语句的解决方法,这很好。 However, just out of curiosity, the question still stands, is there a Perl regex way to have a default if a submatch fails?但是,只是出于好奇,问题仍然存在,如果子匹配失败,是否有 Perl 正则表达式方式具有默认值?

I don't see how to return a list reflecting a changed input.我看不到如何返回反映更改输入的列表。 To change the input we need s{}{}xr operator, so we need code in its replacement part to analyze captures and decide what to change;要更改输入,我们需要s{}{}xr运算符,因此我们需要在其替换部分中使用代码来分析捕获并决定要更改的内容; and, we get a string, not a list, which need be further processed (split).而且,我们得到一个字符串,而不是一个列表,需要进一步处理(拆分)。

Here is then one such take, with a minimal intrusion of code.这是一个这样的例子,对代码的干扰最小。

Match name and value , with = or space between them, and if value ( $2 ) is undefined give it a value;匹配namevalue ,它们之间有=或空格,如果value ( $2 ) 未定义,则给它一个值; so we need /x to do that " if... ".所以我们需要/x来做到这一点“如果... ”。 Once we are at it, put a space between all name-value pairs.完成后,在所有名称-值对之间放置一个空格。 This goes under /r so that the changed string is returned, and passed through split这在/r下,以便返回更改的字符串,并通过split传递

my %arg = split ' ', 
    $args =~ s{ --(\w+) (?: =|\s+|\z) ([^-]\S*)? }{ $1 . " " . ($2//"10 ") }ergx; 

The split can be done by another regex instead but that's still extra processing. split可以由另一个正则表达式代替,但这仍然是额外的处理。

A complete program (where I added more flags to input)一个完整的程序(我在其中添加了更多的标志来输入)

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

my $args = shift // q(--fmt="%H:%M" --f1 --time 12 --f2 --f3);      
say $args;

my %arg = split ' ',
   $args =~ s{ --(\w+) (?: =|\s+|\z) ([^-]\S*)? }{ $1 . ' ' . ($2//'1 ') }ergx; 

say "$_ => $arg{$_}" for keys %arg;

This prints as expected.这按预期打印。


I am not sure why to use regex here.我不知道为什么在这里使用正则表达式。 There are libraries for this, like Getopt::Long .为此有一些库,例如Getopt::Long If this is somehow not possible then processing @ARGV term by term goes nice and easy -- and is fast .如果这在某种程度上是不可能的,那么逐项处理@ARGV会变得又好又容易——而且速度很快

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM