我正在使用 Perl 5.20 為資料轉換工具撰寫復雜的組態檔。
組態檔在加載時和運行時有幾個方面的占位符,封裝了一些路徑代碼,如
# Load time placeholder example
CONFIG: NAME ${/path/pos/*/test/*[123] == 'ABC' }
# Runtime placeholder example
COLUMN: CSV_NAME STRING DEFAULT :{./CSV_FIRST}
出于某種原因,它也應該適用于多行運算式。
我已經使用Text::ParseWord標準分隔符撰寫了掃描儀,并希望在通過不包含 . 的編碼運算式\s 將資料行拆分為單個單詞之前轉義占位符運算式。運算式也是后續資料替換的關鍵。base64\s
轉義由(...參見下面的代碼)定義的模式匹配驅動:
my @pat = $line =~ /([^\\]\Q$pfx\E\{[^\Q$pfx\E\{\}] \})/gs;
例如,${...}當我使用時,哪個 IMO 定義了一個多行模式,但會屏蔽(轉義)運算式。$pfx = '$'\${...}
問題
我在模式的內部掙扎了一段時間...并開始[^\Q$pfx\E\{\}] 作業,但感覺不是正確的,因為
- 它僅包括設定為不使用的符號,
- 但不是外部的順序,
- 例如,防止嵌套運算式。
這樣做的正確表達是什么?
測驗例程
#!/usr/bin/env perl
use strict;
use warnings;
use MIME::Base64;
use feature qw(signatures);
no warnings 'once';
no warnings 'experimental';
no warnings 'experimental::signatures';
my $line =
'# test data
This are:
1. ${/multiline/used/*[3]
= "12345"}
2. ${/single/line/compile/time/pattern/*[3]}
3. ${/single/line/runtime/pattern/x == 1234}
4. ${/multi/line/runtime/pattern \
defer/1 \
defer/2 \
defer/3
}
5. ${//PG.GRM/*[
key eq "TEST.VAR"
]}
';
sub testSpacedPlaceHolder($pfx, $line) {
my %match;
my @pat = $line =~ /([^\\]\Q$pfx\E\{[^\Q$pfx\E\{\}] \})/gs;
my %seen = ();
my @uniq = grep { ! $seen{$_} } @pat;
for my $key (@uniq) {
my $hkey=$pfx.encode_base64($key);
$hkey =~ s/\n//g;
my $var = substr($key, 3, -1);
$match{$hkey}= [ $var, $key ];
$line =~ s/\Q$key\E/$hkey/g;
}
# Test the output ------------------------------
my $cnt = 0;
print "\nRESULT:\n";
for my $key (sort keys %match) {
$cnt ;
my ($var, $orig) = @ { $match{$key} };
print "---- $cnt ----\n";
print "ORG: $orig\n";
print "VAR: $var\n";
print "ESC: $key\n";
}
print "\nLINE:\n$line\n";
return ($line, \%match);
}
testSpacedPlaceHolder('$', $line);
結果
/usr/bin/env perl "test-strings.pl"
RESULT:
---- 1 ----
ORG: ${/multi/line/runtime/pattern \
defer/1 \
defer/2 \
defer/3
}
VAR: /multi/line/runtime/pattern \
defer/1 \
defer/2 \
defer/3
ESC: $ICR7L211bHRpL2xpbmUvcnVudGltZS9wYXR0ZXJuIFwKICAgICAgZGVmZXIvMSBcCiAgICAgIGRlZmVyLzIgXAogICAgICBkZWZlci8zCiAgICAgfQ==
---- 2 ----
ORG: ${/multiline/used/*[3]
= "12345"}
VAR: /multiline/used/*[3]
= "12345"
ESC: $ICR7L211bHRpbGluZS91c2VkLypbM10KICAgICAgPSAiMTIzNDUifQ==
---- 3 ----
ORG: ${/single/line/compile/time/pattern/*[3]}
VAR: /single/line/compile/time/pattern/*[3]
ESC: $ICR7L3NpbmdsZS9saW5lL2NvbXBpbGUvdGltZS9wYXR0ZXJuLypbM119
---- 4 ----
ORG: ${/single/line/runtime/pattern/x == 1234}
VAR: /single/line/runtime/pattern/x == 1234
ESC: $ICR7L3NpbmdsZS9saW5lL3J1bnRpbWUvcGF0dGVybi94ID09IDEyMzR9
---- 5 ----
ORG: ${//PG.GRM/*[
key eq "TEST.VAR"
]}
VAR: //PG.GRM/*[
key eq "TEST.VAR"
]
ESC: $ICR7Ly9QRy5HUk0vKlsKICAgICAgICBrZXkgZXEgIlRFU1QuVkFSIgogICAgICAgXX0=
LINE:
# test data
This are:
1.$ICR7L211bHRpbGluZS91c2VkLypbM10KICAgICAgPSAiMTIzNDUifQ==
2.$ICR7L3NpbmdsZS9saW5lL2NvbXBpbGUvdGltZS9wYXR0ZXJuLypbM119
3.$ICR7L3NpbmdsZS9saW5lL3J1bnRpbWUvcGF0dGVybi94ID09IDEyMzR9
4.$ICR7L211bHRpL2xpbmUvcnVudGltZS9wYXR0ZXJuIFwKICAgICAgZGVmZXIvMSBcCiAgICAgIGRlZmVyLzIgXAogICAgICBkZWZlci8zCiAgICAgfQ==
5.$ICR7Ly9QRy5HUk0vKlsKICAgICAgICBrZXkgZXEgIlRFU1QuVkFSIgogICAgICAgXX0=
編輯
假設我有一個定義某種配置的腳本:
MAGIC: MAGIC.TYPE
CONTAINER: NAME BEGIN
DEFINE: VAR1 'USER.NAME'
DEFINE: VAR2 '65789'
INTERNAL.CONTAINER: INTERNAL.NAME BEGIN
TAG1: 'ABCDEF'
TAG2: ${/NAME/VAR1}
# Unwanted nested variant
TAG3: ${/NAME/VAR1 ${/NAME/VAR2} }
# Valid runtime interpolation variant
TAG4: "${/NAME/VAR1}/:{NAME.KEY}"
# Valid runtime path variant but ignored
TAG5: ${/NAME/VAR1/*/:{TEST{KEY}}
END.INTERNAL.NAME
END.NAME
我想避免嵌套線
# Nested variant
TAG3: ${/NAME/VAR1 ${/NAME/VAR2}}
出于可變的解決原因,但保留
# Valid runtime path variant but ignored
TAG5: ${/NAME/VAR2/*/:{TEST{KEY}}
因為它們是運行時驅動的。
由于簡單的序列,我的變體阻止了 TAG5 [\$\{\}] 。
uj5u.com熱心網友回復:
以下是如何使用遞回正則運算式排除嵌套版本的示例${...}:
use feature qw(say);
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $str = <<'END_STR';
MAGIC: MAGIC.TYPE
CONTAINER: NAME BEGIN
DEFINE: VAR1 'USER.NAME'
DEFINE: VAR2 '65789'
INTERNAL.CONTAINER: INTERNAL.NAME BEGIN
TAG1: 'ABCDEF'
TAG2: ${/NAME/VAR1}
# Unwanted nested variant
TAG3: ${/NAME/VAR1 ${/NAME/VAR2} }
# Valid runtime interpolation variant
TAG4: "${/NAME/VAR1}/:{NAME.KEY}"
# Valid runtime path variant but ignored
TAG5: ${/NAME/VAR1/*/:{TEST{KEY}}}
END.INTERNAL.NAME
END.NAME
END_STR
my @matches;
while ($str =~ /(?:^|(?<!\\))
(?<G3>(?<G1> \$ \{ (?:
(?>(?:[^{}\$\\] | (?:\\.) |
(?<G2> \{ (?: (?>[^{}] ) | (?&G2))* \} ))
| (?<G4>(?&G1))))* \}))/msxg) {
next if defined $ {G4}; # skip nested matches
push @matches, $ {G3};
}
print Dumper(\@matches);
輸出:
$VAR1 = [
'${/NAME/VAR1}',
'${/NAME/VAR1}',
'${/NAME/VAR1/*/:{TEST{KEY}}}'
];
請注意,結果包括 TAG2、TAG4 和 TAG5,但不包括 TAG3。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/425564.html
