当然,您必须根据自己的需要进行调整(最明显的是在读取行时循环),但这是一种不(真正)依赖正则表达式的方法。正如其他人所说,这是一个起点,您可以根据需要进行调整。
#!/usr/bin/perl
use strict;
use warnings;
my $string = 'apple{{mango } guava ; banana; // pear berry;}';
my $new_string = join("\n", grep {/\S/} split(/(\W)/, $string));
print $new_string . "\n";
这会将行拆分为一个数组,拆分非单词字符但保留元素。然后 greps 查找非空白字符(删除包含空白的数组元素)。然后将带有换行符的数组元素连接成一个字符串。根据您的规范所说,您需要 // 一起,我将其作为练习留给读者。
编辑:
再次查看您的请求后,您似乎想要解析一个特定但复杂的结构。要正确执行此操作,您可能必须使用更强大的东西,例如 Regexp::Grammars 模块。这需要一些学习,但您可以定义一组非常复杂的解析指令来完成您需要的任何操作。
编辑 2:
由于我一直在寻找更多了解Regexp::Grammars 的理由,因此我抓住了这个机会。这是我想出的一个基本示例。它将解析的数据结构打印到名为“log.txt”的文件中。我知道它看起来不像您要求的结构,但它包含所有这些信息,并且可以根据您的喜好进行重组。我使用了一个与解析器基本相反的递归函数。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Regexp::Grammars;
my $grammar = qr{
<nocontext:>
<Line>
<rule: Line> <[Element]>*
<rule: Element> <Words> | <Block> | <Command> | <Comment>
<rule: Command> <[Words]> ;
<rule: Block> \{ <[Element]>* \}
<rule: Comment> // .*? \s{2,} #/ Syntax Highlighter fix
<rule: Words> (?:\b\w+\b) ** \s
}x;
my $string = 'apple{{mango kiwi } guava ; banana; // pear berry;}';
if ($string =~ $grammar) {
open my $log, ">", "log.txt";
print $log Dumper \%/; #/
print elements($/{Line}{Element});
} else {
die "Did not match";
}
sub elements {
my @elements = @{ shift() };
my $indent = shift || 0;
my $output;
foreach my $element (@elements) {
$output .= "\t" x $indent;
foreach my $key (keys %$element) {
if ($key eq 'Words') {
$output .= $element->{$key} . "\n";
} elsif ($key eq 'Block') {
$output .= "{\n" . elements($element->{$key}->{Element}, $indent + 1) . ("\t" x $indent) . "}\n";
} elsif ($key eq 'Comment') {
$output .= $element->{$key} . "\n";
} elsif ($key eq 'Command') {
$output .= join(" ", @{ $element->{$key}->{Words} }) . ";\n";
} elsif ($key eq 'Element') {
$output .= elements($element->{$key}, $indent + 1);
}
}
}
return $output;
}
编辑 3:根据 OP 中的 cmets,我已经修改了上面的示例以允许在同一行上显示多个单词,截至目前,这些单词只能用一个空格分隔。我还让 cmets 匹配以 // 开头并以两个或多个空格结尾的任何内容。此外,由于我正在进行更改,并且因为我相信这是一个代码漂亮的打印机,所以我在块格式化程序中添加了制表符。如果不希望这样做,它应该很容易剥离。现在去学习Regexp::Grammars,让它适合你的具体情况。 (我知道我应该让 OP 做这个改变,但我也很喜欢学习它)
编辑 4:还有一件事,如果实际上您正在尝试将有用的代码从序列化代码恢复为单行代码,那么您唯一真正的问题是提取行 cmets 并将它们与有用的代码分开(假设您使用的是空格忽略看起来好像你的语言)。如果是这种情况,那么也许可以在我的原始代码上尝试这种变体:
#!/usr/bin/perl
use strict;
use warnings;
my $string = 'apple{{mango } guava ; banana; // pear berry;}';
my $new_string = join("\n", split(/((?:\/\/).*?\s{2,})/, $string));
print $new_string . "\n";
谁的输出是
apple{{mango } guava ; banana;
// pear
berry;}