【发布时间】:2017-12-06 18:46:31
【问题描述】:
我有一个从网站获取一些数据的脚本。数据采用 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 $1 . ':', BOLD GREEN : $1 . ':'}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 $1, BOLD YELLOW $2, BOLD MAGENTA $3, BOLD RED $4, RESET $5: $1 . $2 . $3 . $4 . $5}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 $1, BOLD YELLOW $2, BOLD MAGENTA $3, RESET $4 : $1 . $2 . $3 . $4}gxmse;
# Colorize 3 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN $1, BOLD YELLOW $2, RESET $3 : $1 . $2 . $3}gxmse;
# Colorize 2 segment flat output
s{([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN $1, RESET $2 : $1 . $2}gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? $1 . BOLD GREEN : $1}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 $1 . ':', BOLD GREEN : $1 . ':'}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 $1, BOLD YELLOW $2, BOLD MAGENTA $3, BOLD RED, $4, RESET $5: $1 . $2 . $3 . $4 . $5}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 $1, BOLD YELLOW $2, BOLD MAGENTA $3, RESET $4 : $1 . $2 . $3 . $4}gxmse;
# Colorize 3 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN $1, BOLD YELLOW $2, RESET $3 : $1 . $2 . $3}gxmse;
# Colorize 2 segment flat output
s{^([a-zA-Z0-9]+:)([a-zA-Z0-9]+:\ )}
{$OPTIONS->{color} ? BOLD CYAN $1, RESET $2 : $1 . $2}gxmse;
# Colorize values in all output
s{(:\ )}
{$OPTIONS->{color} ? $1 . BOLD GREEN : $1}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
扁平化 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 $1 . ':', BOLD GREEN : $1 . ':'}gxmse;
}
# Colorize sections in flat output
if ($OPTIONS->{color})
{
s{$SEGMENT_5PART_RE}
{BOLD CYAN $1, BOLD YELLOW $2, BOLD MAGENTA $3, BOLD RED $4, RESET $5}gxmse;
s{$SEGMENT_4PART_RE}
{BOLD CYAN $1, BOLD YELLOW $2, BOLD MAGENTA $3, RESET $4}gxmse;
s{$SEGMENT_3PART_RE}
{BOLD CYAN $1, BOLD YELLOW $2, RESET $3}gxmse;
s{$SEGMENT_2PART_RE}
{BOLD CYAN $1, RESET $2}gxmse;
# Colorize values in all output
s{(:\ )}{$1 . 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 $1}gxmse;
}
}
return;
}
【问题讨论】:
-
我们需要两种格式的示例数据。如果您真的编写了一个单元测试并将其包含在内,那将是最好的。有关如何为着色内容编写单元测试的示例,请随时向my tests of the module Dancer2::Logger::Console::Colored 借用。
-
如果任务是为 YAML 着色,您还可以查看YAML::PP(免责声明:来自我自己)。它可以突出显示 YAML,并且由于 YAML(几乎)是 JSON 的超集,它也可以为 JSON 着色。但我认为目前的突出显示与您想要的不同。
-
@tinita 不幸的是,运行代码和下载数据的机器没有外部网络访问权限,只能访问内部和我们工程师构建的特定存储库。因此,我正在使用 YAML::Tiny,但无法从 CPAN 或其他地方安装 YAML::PP。 :-(
-
@simbabque 我会研究单元测试。我将以所有 4 种格式(json、扁平化 json、json 转换为 yaml 和扁平化 json 转换为 yaml)发布示例数据——很快
-
好的。伟大的。我还有大约一个半小时的火车车程。 :)
标签: perl code-duplication