我有一个很大的连续文字,其中包含{, },//,;
等字符,中间有空格。我想阅读这篇文章,并在找到这些字符的任何地方写入新行。
输入文字如下:
apple{{mango } guava ; banana; // pear berry;}
预期的格式化输出数据应如图所示
apple
{
{
mango
}
guava ;
banana;
// pear
berry;
}
我想在 perl 中执行此操作。提前感谢。
答案 0 :(得分:4)
当然你必须根据你的需要调整它(最明显的是在读取行时循环),但这是一种不(真的)依赖正则表达式的方法。正如其他人所说,这是一个起点,你可以适应你的需要。
#!/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的评论,我已经调整了上面的例子以允许在同一行上有多个单词,现在这些单词只能用一个空格分隔。我还发表评论,匹配从//
开始并以两个或多个空格结束的任何内容。此外,由于我正在进行更改,并且由于我认为这是一个代码漂亮的打印机,我添加了tabbing到块格式化程序。如果不希望这样,它应该很容易剥离。现在就去学习Regexp::Grammars
并使其适合您的具体情况。 (我知道我应该让OP做这个改变,但我也很乐意学习它)
编辑4:还有一件事,如果实际上你试图将有用的代码从序列化恢复到单行代码,你唯一真正的问题是提取行注释并将它们与有用的代码分开(假设你使用的是空白忽略了它看起来像你的语言。如果是这种情况,那么也许可以在原始代码上尝试这种变化:
#!/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;}
答案 1 :(得分:3)
您的规格很糟糕。有时你需要前后换行。有时你想要一个换行符。有时你想要换行。您在单独的行上有“梨”和“浆果”,但它不符合您的规范中的任何条件。
答案的质量与撰写问题时给予的关注成正比。
如果有一个粗心的问题,你可能会得到一个粗心的答案。
#!/usr/bin/perl
use warnings;
use strict;
$_ = 'apple{{mango } guava ; banana; // pear berry;}';
s#([{}])#\n$1\n#g; # curlies
s#;#;\n#g; # semicolons
s#//#\n//#g; # double slashes
s#\s\s+#\n#g; # 2 or more whitespace
s#\n\n#\n#g; # no blank lines
print;
答案 2 :(得分:1)
不完全是你想要的,但是imho的开始就足够了:
echo 'apple{{mango } guava ; banana; // pear berry;}' |\
perl -ple 's/(\b\w+\b)/\n$1\n/g'
将产生:
apple
{{
mango
}
guava
;
banana
; //
pear
berry
;}
你可以开始改进它......
答案 3 :(得分:1)
正如你所说,这不是家庭作业,我想到了以下内容:
my $keeps = qr#(//\s+\w+)#; #special tokens to keep (e.g., // perl) my $breaks = qr#(\s+|\[|\]|\{|\})#; #simple tokens to split words at while ( my $text = <> ) { @tokens = grep /\S/, split( qr($keeps|$breaks), $text ); print join(".\n.", @tokens ), "\n"; }
您必须自己制定实际规则。