在perl中合并2个几乎相同的函数
Merging 2 nearly identical functions in perl
我有一个脚本可以从网站获取一些数据。数据采用 JSON 格式,站点提供了一个选项,可以将 JSON 输出到单个 JSON 对象中,或者将其保留为多个对象。
该脚本的选项允许将 JSON 数据转换为 YAML(无论是否扁平化),或将其保留为 JSON 格式。
此外,脚本还为两种格式的值着色。
为了完成着色,我目前有2个函数,一个是JSON着色,一个是YAML着色。
着色本身是通过 Term::ANSIColor 通过搜索和替换标量或数组中的文本来实现的,具体取决于数据的输出格式。
我想将其简化为一个函数以减少代码重复,但我不知道如何实现这一点。
为了清楚起见,为了清楚起见,这个问题的主要焦点是如何使其中一个着色函数可重用,以便它可以在 YAML 和JSON 输出。因为搜索模式非常相似,替换模式也相同,我觉得完成这个应该很容易,但我对如何做一无所知。
use JSON;
use YAML::Tiny;
sub colorize_yaml
{
my $OUTPUT = shift;
my $OPTIONS = shift;
if (ref $OUTPUT eq 'SCALAR')
{
foreach (${$OUTPUT})
{
# Hide this if debugging is disabled, else show it and color it
if (!$OPTIONS->{debug})
{
s{(statusCode|success|dataExist|verumModelObjectName):\ [a-zA-Z0-9]+\n}
{}gxms;
}
else
{
s{(statusCode|success|dataExist|verumModelObjectName):}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
# Colorize 5 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED , RESET : . . . . }gxmse;
# Colorize 4 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET : . . . }gxmse;
# Colorize 3 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , RESET : . . }gxmse;
# Colorize 2 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , RESET : . }gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? . BOLD GREEN : }gxmse;
# Reset colors before newlines so that the next line starts with a clean color pattern.
s{\n}
{$OPTIONS->{color} ? RESET "\n" : "\n"}gxmse;
}
}
else
{
pretty_print_error("WARNING: Unable to colorize YAML output\n", $OPTIONS->{color});
return;
}
return;
}
sub colorize_json
{
my $OUTPUT = shift;
my $OPTIONS = shift;
if (ref $OUTPUT eq 'ARRAY')
{
foreach (@{$OUTPUT})
{
if ($OPTIONS->{debug})
{
s{(statusCode|success|dataExist|verumModelObjectName):}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
else
{
s{(statusCode|success|dataExist|verumModelObjectName):\ [a-zA-Z0-9]+\n}
{}gxms;
}
# Colorize 5 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ .*$)}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED, , RESET : . . . . }gxmse;
# Colorize 4 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET : . . . }gxmse;
# Colorize 3 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , RESET : . . }gxmse;
# Colorize 2 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , RESET : . }gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? . BOLD GREEN : }gxmse;
# Reset colors before newlines so that the next line starts with a clean color pattern.
s{$}
{$OPTIONS->{color} ? RESET '' : ''}gxmse;
}
}
else
{
pretty_print_error("WARNING: Unable to colorize JSON output.\n", $OPTIONS->{color});
return;
}
return;
}
JSON 转换为 YAML
---
message: Success
ObjectList:
-
assetName: xxxxxxxx
backupAsset:
-
backupFlag: xxxxxxxx
fullyCertified: xxxxxxxx
扁平化JSON 转换为 YAML
---
message: Success
verumObjectList:
-
assetName: xxxxxxxx
backupAsset:backupFlag: xxxxxxxx
backupAsset:fullyCertified: xxxxxxxx
JSON(JSON格式的数据被脚本剥离为纯文本)
assetName: xxxxxxxx
backupFlag: xxxxxxxx
fullyCertified: xxxxxxxx
message: Success
Flattened JSON(JSON格式的数据被脚本剥离为纯文本)
assetName: xxxxxxxx
backupAsset:backupFlag: xxxxxxxx
backupAsset:fullyCertified: xxxxxxxx
message: Success
正确答案授予@zdim,尽管我确实需要稍微调整一下代码。
我在下面发布更新后的代码。
use JSON;
use YAML::Tiny;
sub colorize_output
{
my $OUTPUT = shift;
my $OPTIONS = shift;
my $RE_START = $EMPTY;
my $RE_END = q{\ };
if (ref $OUTPUT eq $EMPTY)
{
pretty_print_error("WARNING: Unable to colorize output.\n",
$OPTIONS->{color});
return;
}
elsif (ref $OUTPUT eq 'ARRAY')
{
$RE_START = q{^};
$RE_END = q{\ .*};
}
my $ANCHOR = q{[a-zA-Z0-9]+:};
my $PATTERN = qq{($ANCHOR)};
Readonly my $SEGMENT_LIMIT => 4;
my $VERUM_RE = qr{(statusCode|success|dataExist|verumModelObjectName):}xms;
my ($SEGMENT_2PART_RE, $SEGMENT_3PART_RE, $SEGMENT_4PART_RE, $SEGMENT_5PART_RE)
= map {
qr{$RE_START}xms . ($PATTERN x $ARG) . qr{($ANCHOR$RE_END)}xms
} 1..$SEGMENT_LIMIT;
foreach ((ref $OUTPUT eq 'SCALAR')?${$OUTPUT}:@{$OUTPUT})
{
# Hide this if debugging is disabled, else show it and color it
if (!$OPTIONS->{debug})
{
s{$VERUM_RE\ [a-zA-Z0-9]+}{}gxms;
}
else
{
s{$VERUM_RE}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
# Colorize sections in flat output
if ($OPTIONS->{color})
{
s{$SEGMENT_5PART_RE}
{BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED , RESET }gxmse;
s{$SEGMENT_4PART_RE}
{BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET }gxmse;
s{$SEGMENT_3PART_RE}
{BOLD CYAN , BOLD YELLOW , RESET }gxmse;
s{$SEGMENT_2PART_RE}
{BOLD CYAN , RESET }gxmse;
# Colorize values in all output
s{(:\ )}{ . BOLD GREEN}gxmse;
# Reset colors before newlines or next entry in the list so that
# the next line starts with a clean color pattern.
s{(\n|$)}{RESET }gxmse;
}
}
return;
}
这回答了如何重构这些功能的问题,没有任何更广泛的上下文。
一个区别是输入:它是标量引用或数组引用。
正则表达式中涉及更多的另外两个差异:arrayref 模式是锚定的,它们的最后一个字母数字模式以 \ .*$
结尾,而 scalarref 模式不是锚定的,它们的最后一个匹配以转义的 [=35] 结尾=].
最后,如果 $OPTIONS->{color}
为假,那么在所有情况下,整个模式都会被自身替换;所以变量不会改变。那么条件就应该拉出来了。
sub colorize_yaml_json {
my ($OUTPUT, $OPTIONS) = @_;
my $anchor = '';
my $last = qr{\ };
my @iter_refs;
if (ref $OUTPUT eq 'SCALAR') { @iter_refs = $$OUTPUT }
elsif (ref $OUTPUT eq 'ARRAY') {
@iter_refs = @$OUTPUT;
$anchor = qr{^};
$last = qr{\ .*$};
}
else {
pretty_print_error(...);
return;
}
my $anc = qr{[a-zA-Z0-9]+:}; # alphanumeric with colon
my $patt = qr{($anc)};
my ($seg2_re, $seg3_re, $seg4_re, $seg5_re) = map {
qr/$anchor/ . ($patt x $_) . qr/($anc$last)/
} 1..4;
foreach (@iter_refs) {
if ($OPTIONS->{debug}) {
...
}
if ($OPTIONS->{color}) {
s{$seg5_re}{BOLD CYAN , ... }gxmse;
...
}
}
return 1;
}
map
通过将字母数字(使用 :
)模式 $patt
堆叠所需的 2-5 次,使用 [=16= 为四种情况组装整个模式] 对于 1..4
,然后附加最后一个模式。
令人不快的并发症是每个基本模式 $anc
都需要被捕获。
我只能在我的模型数据上对此进行测试,所以请仔细检查(一如既往!)。
还有另一个问题是如何最好地处理整个场景,但这不是问题所在,因此没有足够的信息来处理它而无需太多猜测。
我有一个脚本可以从网站获取一些数据。数据采用 JSON 格式,站点提供了一个选项,可以将 JSON 输出到单个 JSON 对象中,或者将其保留为多个对象。
该脚本的选项允许将 JSON 数据转换为 YAML(无论是否扁平化),或将其保留为 JSON 格式。
此外,脚本还为两种格式的值着色。
为了完成着色,我目前有2个函数,一个是JSON着色,一个是YAML着色。
着色本身是通过 Term::ANSIColor 通过搜索和替换标量或数组中的文本来实现的,具体取决于数据的输出格式。
我想将其简化为一个函数以减少代码重复,但我不知道如何实现这一点。
为了清楚起见,为了清楚起见,这个问题的主要焦点是如何使其中一个着色函数可重用,以便它可以在 YAML 和JSON 输出。因为搜索模式非常相似,替换模式也相同,我觉得完成这个应该很容易,但我对如何做一无所知。
use JSON;
use YAML::Tiny;
sub colorize_yaml
{
my $OUTPUT = shift;
my $OPTIONS = shift;
if (ref $OUTPUT eq 'SCALAR')
{
foreach (${$OUTPUT})
{
# Hide this if debugging is disabled, else show it and color it
if (!$OPTIONS->{debug})
{
s{(statusCode|success|dataExist|verumModelObjectName):\ [a-zA-Z0-9]+\n}
{}gxms;
}
else
{
s{(statusCode|success|dataExist|verumModelObjectName):}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
# Colorize 5 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED , RESET : . . . . }gxmse;
# Colorize 4 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET : . . . }gxmse;
# Colorize 3 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , RESET : . . }gxmse;
# Colorize 2 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , RESET : . }gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? . BOLD GREEN : }gxmse;
# Reset colors before newlines so that the next line starts with a clean color pattern.
s{\n}
{$OPTIONS->{color} ? RESET "\n" : "\n"}gxmse;
}
}
else
{
pretty_print_error("WARNING: Unable to colorize YAML output\n", $OPTIONS->{color});
return;
}
return;
}
sub colorize_json
{
my $OUTPUT = shift;
my $OPTIONS = shift;
if (ref $OUTPUT eq 'ARRAY')
{
foreach (@{$OUTPUT})
{
if ($OPTIONS->{debug})
{
s{(statusCode|success|dataExist|verumModelObjectName):}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
else
{
s{(statusCode|success|dataExist|verumModelObjectName):\ [a-zA-Z0-9]+\n}
{}gxms;
}
# Colorize 5 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ .*$)}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED, , RESET : . . . . }gxmse;
# Colorize 4 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET : . . . }gxmse;
# Colorize 3 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , BOLD YELLOW , RESET : . . }gxmse;
# Colorize 2 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN , RESET : . }gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? . BOLD GREEN : }gxmse;
# Reset colors before newlines so that the next line starts with a clean color pattern.
s{$}
{$OPTIONS->{color} ? RESET '' : ''}gxmse;
}
}
else
{
pretty_print_error("WARNING: Unable to colorize JSON output.\n", $OPTIONS->{color});
return;
}
return;
}
JSON 转换为 YAML
---
message: Success
ObjectList:
-
assetName: xxxxxxxx
backupAsset:
-
backupFlag: xxxxxxxx
fullyCertified: xxxxxxxx
扁平化JSON 转换为 YAML
---
message: Success
verumObjectList:
-
assetName: xxxxxxxx
backupAsset:backupFlag: xxxxxxxx
backupAsset:fullyCertified: xxxxxxxx
JSON(JSON格式的数据被脚本剥离为纯文本)
assetName: xxxxxxxx
backupFlag: xxxxxxxx
fullyCertified: xxxxxxxx
message: Success
Flattened JSON(JSON格式的数据被脚本剥离为纯文本)
assetName: xxxxxxxx
backupAsset:backupFlag: xxxxxxxx
backupAsset:fullyCertified: xxxxxxxx
message: Success
正确答案授予@zdim,尽管我确实需要稍微调整一下代码。
我在下面发布更新后的代码。
use JSON;
use YAML::Tiny;
sub colorize_output
{
my $OUTPUT = shift;
my $OPTIONS = shift;
my $RE_START = $EMPTY;
my $RE_END = q{\ };
if (ref $OUTPUT eq $EMPTY)
{
pretty_print_error("WARNING: Unable to colorize output.\n",
$OPTIONS->{color});
return;
}
elsif (ref $OUTPUT eq 'ARRAY')
{
$RE_START = q{^};
$RE_END = q{\ .*};
}
my $ANCHOR = q{[a-zA-Z0-9]+:};
my $PATTERN = qq{($ANCHOR)};
Readonly my $SEGMENT_LIMIT => 4;
my $VERUM_RE = qr{(statusCode|success|dataExist|verumModelObjectName):}xms;
my ($SEGMENT_2PART_RE, $SEGMENT_3PART_RE, $SEGMENT_4PART_RE, $SEGMENT_5PART_RE)
= map {
qr{$RE_START}xms . ($PATTERN x $ARG) . qr{($ANCHOR$RE_END)}xms
} 1..$SEGMENT_LIMIT;
foreach ((ref $OUTPUT eq 'SCALAR')?${$OUTPUT}:@{$OUTPUT})
{
# Hide this if debugging is disabled, else show it and color it
if (!$OPTIONS->{debug})
{
s{$VERUM_RE\ [a-zA-Z0-9]+}{}gxms;
}
else
{
s{$VERUM_RE}
{$OPTIONS->{color} ? BOLD YELLOW . ':', BOLD GREEN : . ':'}gxmse;
}
# Colorize sections in flat output
if ($OPTIONS->{color})
{
s{$SEGMENT_5PART_RE}
{BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , BOLD RED , RESET }gxmse;
s{$SEGMENT_4PART_RE}
{BOLD CYAN , BOLD YELLOW , BOLD MAGENTA , RESET }gxmse;
s{$SEGMENT_3PART_RE}
{BOLD CYAN , BOLD YELLOW , RESET }gxmse;
s{$SEGMENT_2PART_RE}
{BOLD CYAN , RESET }gxmse;
# Colorize values in all output
s{(:\ )}{ . BOLD GREEN}gxmse;
# Reset colors before newlines or next entry in the list so that
# the next line starts with a clean color pattern.
s{(\n|$)}{RESET }gxmse;
}
}
return;
}
这回答了如何重构这些功能的问题,没有任何更广泛的上下文。
一个区别是输入:它是标量引用或数组引用。
正则表达式中涉及更多的另外两个差异:arrayref 模式是锚定的,它们的最后一个字母数字模式以 \ .*$
结尾,而 scalarref 模式不是锚定的,它们的最后一个匹配以转义的 [=35] 结尾=].
最后,如果 $OPTIONS->{color}
为假,那么在所有情况下,整个模式都会被自身替换;所以变量不会改变。那么条件就应该拉出来了。
sub colorize_yaml_json {
my ($OUTPUT, $OPTIONS) = @_;
my $anchor = '';
my $last = qr{\ };
my @iter_refs;
if (ref $OUTPUT eq 'SCALAR') { @iter_refs = $$OUTPUT }
elsif (ref $OUTPUT eq 'ARRAY') {
@iter_refs = @$OUTPUT;
$anchor = qr{^};
$last = qr{\ .*$};
}
else {
pretty_print_error(...);
return;
}
my $anc = qr{[a-zA-Z0-9]+:}; # alphanumeric with colon
my $patt = qr{($anc)};
my ($seg2_re, $seg3_re, $seg4_re, $seg5_re) = map {
qr/$anchor/ . ($patt x $_) . qr/($anc$last)/
} 1..4;
foreach (@iter_refs) {
if ($OPTIONS->{debug}) {
...
}
if ($OPTIONS->{color}) {
s{$seg5_re}{BOLD CYAN , ... }gxmse;
...
}
}
return 1;
}
map
通过将字母数字(使用 :
)模式 $patt
堆叠所需的 2-5 次,使用 [=16= 为四种情况组装整个模式] 对于 1..4
,然后附加最后一个模式。
令人不快的并发症是每个基本模式 $anc
都需要被捕获。
我只能在我的模型数据上对此进行测试,所以请仔细检查(一如既往!)。
还有另一个问题是如何最好地处理整个场景,但这不是问题所在,因此没有足够的信息来处理它而无需太多猜测。