正規表現のマッチングのカスタム文
-
20-09-2019 - |
質問
って書かの正規表現の試合や分割、カスタム変数の構文クライアントまで、フルのC#.の考えがここにあるカスタムフォーマット文字列の値も同様とします。純文字列になります。形式/{0}のスタイルの文字列フォーマット
例えば、ユーザー定義される文字列形式で評価される実行時にはこのように:
D:\Path\{LanguageId}\{PersonId}\
の価値LanguageId'と一致するデータオブジェクト分野現在の値に置き換え.
で取り上げるべきだったトリッキーが必要な時に引数を渡すにはライブラリリファレンスを参照す。例えば:
{LanguageId:English|Spanish|French}
ことばの意味を実行す条件付きロジックの場合の値LanguageId'と同等の論争することができます。
最後に私をサポートする必要がある図の引数ようになります:
{LanguageId:English=>D:\path\english.xml|Spanish=>D:\path\spansih.xml}
この列挙すべての戻り値:
コマンド引数を指定しない:何か特別な
{@Date}
コマンドは単一の引数:
{@Date:yyyy-mm-dd}
引数を指定しない:
{LanguageId}
単一引数のリスト:
{LanguageId:English}
多数の引数リスト:
{LanguageId:English|Spanish}
単一の引数マップ:
{LanguageId:English=>D:\path\english.xml}
多数の引数マップ:
{LanguageId:English=>D:\path\english.xml|Spanish=>D:\path\spansih.xml}
概要:の書式で煮詰め、キーはオプションパラメータ型のリストや地図ない。
以下は、Regexいるいくつかの問題、すなわちズで扱うすべての空白文字を正しく社までお問い合わせください。純あまりないと思いますので分割しい文化を用いて作られています。たとえば最初の例では私が返されるシングルマッチの'{LanguageId}{PersonId}'の代わりに二つの異なる。も思うのだが、対応ファイルシステムのパス、または区切りの表示文字列です。のお役に立てるよう気をぶよりお願い申し上げます。又は提言しています。
private const string RegexMatch = @"
\{ # opening curly brace
[\s]* # whitespace before command
@? # command indicator
(.[^\}\|])+ # string characters represening command or metadata
( # begin grouping of params
: # required param separater
( # begin select list param type
( # begin group of list param type
.+[^\}\|] # string of characters for the list item
(\|.+[^\}\|])* # optional multiple list items with separator
) # end select list param type
| # or select map param type
( # begin group of map param type
.+[^\}\|]=>.+[^\}\|] # string of characters for map key=>value pair
(\|.+[^\}\|]=>.+[^\}\|])* # optional multiple param map items
) # end group map param type
) # end select map param type
) # end grouping of params
? # allow at most 1 param group
\s*
\} # closing curly brace
";
解決
だいくつregex.ていただきたいのタスクの下の階段をはじめ、簡単な試合うように見えます。この正規表現できると:
\{\s*([^{}]+?)\s*\}
省全体の変数/コマンド文字列はグループ#1、マイナスのブレースと周囲の白文字。その後、分割することができるコロン、パイプ、そして "=>"
配列として適しています。な圧縮すべての複雑性を一つのモンスター regex;ばれるもので管理し、regex記述するので維持が要件の変更ます。
そしてもうひとつ:今だけのもののコードが入力が正しい場合、ユーザーで間違いだったのか?なんとしてもです。Regexes吸えること。彼らは厳しくパス/失敗します。Regexesできる驚くほど役に立つものように他のツールは、その限界を前に、これまでのハーネス自。
他のヒント
いち"などを実施していFinate状態機械ではなく、正規表現を中心に、速puropses. http://en.wikipedia.org/wiki/Finite-state_machine
編集:実際に、正確に、見たいと思い決定性有限状態機械: http://en.wikipedia.org/wiki/Deterministic_finite-state_machine
こうするとの解析が続けられます。
例はなかったり、この構文解析を用い Regexp::Grammars
.
ください言い訳の長さです。
#! /opt/perl/bin/perl
use strict;
use warnings;
use 5.10.1;
use Regexp::Grammars;
my $grammar = qr{
^<Path>$
<objtoken: My::Path>
<drive=([a-zA-Z])>:\\ <[elements=PathElement]> ** (\\) \\?
<rule: PathElement>
(?:
<MATCH=BlockPathElement>
|
<MATCH=SimplePathElement>
)
<token: SimplePathElement>
(?<= \\ ) <MATCH=([^\\]+)>
<rule: My::BlockPathElement>
(?<=\\){ \s*
(?|
<MATCH=Command>
|
<MATCH=Variable>
)
\s* }
<objrule: My::Variable>
<name=(\w++)> <options=VariableOptionList>?
<rule: VariableOptionList>
:
<[MATCH=VariableOptionItem]> ** ([|])
<token: VariableOptionItem>
(?:
<MATCH=VariableOptionMap>
|
<MATCH=( [^{}|]+? )>
)
<objrule: My::VariableOptionMap>
\s*
<name=(\w++)> => <value=([^{}|]+?)>
\s*
<objrule: My::Command>
@ <name=(\w++)>
(?:
: <[arg=CommandArg]> ** ([|])
)?
<token: CommandArg>
<MATCH=([^{}|]+?)> \s*
}x;
試験:
use YAML;
while( my $line = <> ){
chomp $line;
local %/;
if( $line =~ $grammar ){
say Dump \%/;
}else{
die "Error: $line\n";
}
}
サンプルデータ:
D:\Path\{LanguageId}\{PersonId} E:\{ LanguageId : English | Spanish | French } F:\Some Thing\{ LanguageId : English => D:\path\english.xml | Spanish => D:\path\spanish.xml } C:\{@command} c:\{@command :arg} c:\{ @command : arg1 | arg2 }
このように表示されます:
---
'': 'D:\Path\{LanguageId}\{PersonId}'
Path: !!perl/hash:My::Path
'': 'D:\Path\{LanguageId}\{PersonId}'
drive: D
elements:
- Path
- !!perl/hash:My::Variable
'': LanguageId
name: LanguageId
- !!perl/hash:My::Variable
'': PersonId
name: PersonId
---
'': 'E:\{ LanguageId : English | Spanish | French }'
Path: !!perl/hash:My::Path
'': 'E:\{ LanguageId : English | Spanish | French }'
drive: E
elements:
- !!perl/hash:My::Variable
'': 'LanguageId : English | Spanish | French'
name: LanguageId
options:
- English
- Spanish
- French
---
'': 'F:\Some Thing\{ LanguageId : English => D:\path\english.xml | Spanish => D:\path\spanish.xml }'
Path: !!perl/hash:My::Path
'': 'F:\Some Thing\{ LanguageId : English => D:\path\english.xml | Spanish => D:\path\spanish.xml }'
drive: F
elements:
- Some Thing
- !!perl/hash:My::Variable
'': 'LanguageId : English => D:\path\english.xml | Spanish => D:\path\spanish.xml '
name: LanguageId
options:
- !!perl/hash:My::VariableOptionMap
'': 'English => D:\path\english.xml '
name: English
value: D:\path\english.xml
- !!perl/hash:My::VariableOptionMap
'': 'Spanish => D:\path\spanish.xml '
name: Spanish
value: D:\path\spanish.xml
---
'': 'C:\{@command}'
Path: !!perl/hash:My::Path
'': 'C:\{@command}'
drive: C
elements:
- !!perl/hash:My::Command
'': '@command'
name: command
---
'': 'c:\{@command :arg}'
Path: !!perl/hash:My::Path
'': 'c:\{@command :arg}'
drive: c
elements:
- !!perl/hash:My::Command
'': '@command :arg'
arg:
- arg
name: command
---
'': 'c:\{ @command : arg1 | arg2 }'
Path: !!perl/hash:My::Path
'': 'c:\{ @command : arg1 | arg2 }'
drive: c
elements:
- !!perl/hash:My::Command
'': '@command : arg1 | arg2 '
arg:
- arg1
- arg2
name: command
サンプルプログラム:
my %ARGS = qw'
LanguageId English
PersonId someone
';
while( my $line = <> ){
chomp $line;
local %/;
if( $line =~ $grammar ){
say $/{Path}->fill( %ARGS );
}else{
say 'Error: ', $line;
}
}
{
package My::Path;
sub fill{
my($self,%args) = @_;
my $out = $self->{drive}.':';
for my $element ( @{ $self->{elements} } ){
if( ref $element ){
$out .= '\\' . $element->fill(%args);
}else{
$out .= "\\$element";
}
}
return $out;
}
}
{
package My::Variable;
sub fill{
my($self,%args) = @_;
my $name = $self->{name};
if( exists $args{$name} ){
$self->_fill( $args{$name} );
}else{
my $lc_name = lc $name;
my @possible = grep {
lc $_ eq $lc_name
} keys %args;
die qq'Cannot find argument for variable "$name"\n' unless @possible;
if( @possible > 1 ){
my $die = qq'Cannot determine which argument matches "$name" closer:\n';
for my $possible( @possible ){
$die .= qq' "$possible"\n';
}
die $die;
}
$self->_fill( $args{$possible[1]} );
}
}
sub _fill{
my($self,$opt) = @_;
# This is just an example.
unless( exists $self->{options} ){
return $opt;
}
for my $element ( @{$self->{options}} ){
if( ref $element ){
return '['.$element->value.']' if lc $element->name eq lc $opt;
}elsif( lc $element eq lc $opt ){
return $opt;
}
}
my $name = $self->{name};
my $die = qq'Invalid argument "$opt" for "$name" :\n';
for my $valid ( @{$self->{options}} ){
$die .= qq' "$valid"\n';
}
die $die;
}
}
{
package My::VariableOptionMap;
sub name{
my($self) = @_;
return $self->{name};
}
}
{
package My::Command;
sub fill{
my($self,%args) = @_;
return '['.$self->{''}.']';
}
}
{
package My::VariableOptionMap;
sub name{
my($self) = @_;
return $self->{name};
}
sub value{
my($self) = @_;
return $self->{value};
}
}
出力を使用例データ
D:\Path\English\someone E:\English F:\Some Thing\[D:\path\english.xml] C:\[@command] c:\[@command :arg] c:\[@command : arg1 | arg2 ]