Perl:在找到特定字符时将文本写入新行

Perl:在找到特定字符时将文本写入新行,perl,Perl,我有一个大的连续文本,上面有{,},//,;中间有空白。我想读这篇文章,并在找到这些字符的地方写进新行 输入文本如下所示: 预期的格式化输出数据应如图所示 我想用perl来做这件事。提前谢谢。你的规范太差劲了。有时你需要前后换行。有时你想在之后换行。有时候你需要一条新的线路。你有梨和浆果在不同的线,但它不符合任何条件在你的规格 答案的质量与撰写问题时的谨慎程度成正比 一个粗心的问题,你很可能会得到一个粗心的答案 #!/usr/bin/perl use warnings; use strict;

我有一个大的连续文本,上面有{,},//,;中间有空白。我想读这篇文章,并在找到这些字符的地方写进新行

输入文本如下所示:

预期的格式化输出数据应如图所示


我想用perl来做这件事。提前谢谢。

你的规范太差劲了。有时你需要前后换行。有时你想在之后换行。有时候你需要一条新的线路。你有梨和浆果在不同的线,但它不符合任何条件在你的规格

答案的质量与撰写问题时的谨慎程度成正比

一个粗心的问题,你很可能会得到一个粗心的答案

#!/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;

这并不完全是你想要的,但我一开始就足够了:

echo 'apple{{mango } guava ; banana; // pear      berry;}' |\
perl -ple 's/(\b\w+\b)/\n$1\n/g'
将产生:

apple
{{
mango
 } 
guava
 ; 
banana
; // 
pear

berry
;}

您可以开始改进它…

当然,您必须根据自己的需要调整它,尤其是在阅读行时循环,但这里有一种方法可以做到这一点,它并不真正依赖正则表达式。正如其他人所说,这是一个起点,你可以适应你需要的

#!/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。然后将带有换行符的数组元素合并为一个字符串。根据您的规格说明,您需要//一起使用,我将此作为练习留给读者

编辑: 在再次查看您的请求之后,看起来您正试图解析一个特定但复杂的结构。要正确地执行此操作,您可能需要使用功能更强大的模块。这需要一些学习,但您可以定义一组非常复杂的解析指令,以完全执行您需要的任何操作

#!/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";
编辑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;
}
谁的输出是

apple{{mango } guava ; banana; 
// pear      
berry;}

正如你所说,这不是家庭作业,我想到了以下几点:

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"; }
你必须自己制定实际的规则。

完全同意你的观点。他的问题不够清晰。pear和berry之间有很长的空白……我是perl新手……我想这类问题对你来说可能听起来很基本……无论如何,我感谢你的帮助。@Sumit:基本问题很棒。但考虑不周的就不是了。您需要以清晰简洁的方式定义您的规范,然后才能将其应用于代码。有条理、清晰地表达自己并没有什么先进之处。@DavidO这篇文章将是一大行,而不是像芒果或苹果这样的世界……就像阅读一大行文字一样。逐字检查是否存在此类缺陷;{ } . 当它发生时,将读取的文本打印到新行中,并在新行中打印此特殊字符。继续读这行,直到这种情况再次发生…@jm666 Thx这将起作用…如何-ple的/\b\w+\b/\n$1\n/g'这将起作用…@jm666…这将与实际文件中的文本不完全相同…在大文件中,我必须阅读文本,直到像这样的字符;{}出现…然后将读取的文本打印到新行…再次继续阅读,直到下次再次出现,然后继续loop@jm666这篇文章将是一大行,而不是像芒果或苹果这样的世界……就像阅读一大行文字一样。逐字检查是否存在此类缺陷;{ } . 当它发生时,将读取的文本打印到新行中,并在新行中打印此特殊字符。继续读这行,直到再次出现这种情况……简单地告诉你哪些字符应该作为行分隔符,所以在你想让哪些字符断行之前。@jm666从逻辑上讲,你说的话听起来正是我想要的。。你能建议我试着这样做吗:$line{while$line=~/./g{$line=~s/\n/;$line=~s/}/\n/}}每次找到这样的字符时,它都会将文本分成新行,但会漏掉这个字符……它可以工作,只是在每个单词处都会分成新行。。。。不仅仅是特殊字符…任何建议…@Sumit,我认为你所做的是解析更复杂的东西。您必须调整规则以适应现有的结构。甚至你的例子也不只是在特殊字符上分裂;注释机制//单词多个空格是一行。此框架将允许您声明要逻辑匹配的不同类型的结构。如果我想得太多,那么我道歉,不过,我猜你是
e打印一些编程语言,您需要比在特殊字符上拆分做得更好。@Sumit,您可以添加+之类的规则,并使元素规则|。。。。这将使多个单词保持在一个块中。您还必须修改递归函数来处理这个问题。注意:这没有经过测试,在我看来,可能会破坏命令规则,您可能需要更改为;可能还有其他的清理工作。你应该能自己从这里适应它。我承认这并不容易,但它是强大、灵活和合乎逻辑的。一旦你做对了,它会很好地为你服务。@Sumit,我已经更新了示例,因为我对解决方案感兴趣,从现在开始,使用/调整它以满足你的需要。@joel..thx谢谢你在那里纠正我…是的,它不会在/…处中断。我正在尝试学习regexp:grammar。。。。
apple{{mango } guava ; banana; 
// pear      
berry;}
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"; }