2012-01-31 105 views
1

如何使用perl搜索两个顺序换行符(\ n)?或者更具体地说,为什么即使它们存在,搜索也不成功?我有一个连续换行符的文件(使用十六进制编辑器来完成,它们不是返回值等),但是perl似乎并不接受这个正则表达式。如何使用perl搜索两个连续换行符( n)?

的perl -pi -e 'S/\ n \ n /测试/ G' 将myfile.xml =没有结果

实际上,我试图插入一些代码到XML文件,但换行符在中间,那么最优雅的方式是什么?我想出了一个可怕的perl单行文本,但是双行文件似乎会导致失败。

我想改变从一个gtkrc文件的一部分:

GtkWidget::link-color = @link_color 
GtkWidget::visited-link-color = @text_color 

#################### 
# Color Definitions 
#################### 

到:

GtkWidget::link-color = @link_color 
GtkWidget::visited-link-color = @text_color 

GtkWindow::resize-grip-height = 0 
GtkWindow::resize-grip-width = 0 

#################### 
# Color Definitions 
#################### 

使用的原代码的一部分作为我的搜索词(也有各自之前的标签在原始脚本线上,顺便说一句),我的查找和替换条款是:

color\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color 

color\n\n\tGtkWindow::resize-grip-height = 0\n\tGtkWindow::resize-grip-width = 0\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color 

我想出了这个大ugl Ÿperl的命令:

perl -pi -e 's/color\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color/color\n\n\tGtkWindow::resize-grip-height = 0\n\tGtkWindow::resize-grip-width = 0\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color/g' /usr/share/themes/Ambiance/gtk-2.0/gtkrc 

编辑:从扎伊德更正代码:

perl -0777 -pi -e 's/color\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color/color\n\n\tGtkWindow::resize-grip-height = 0\n\tGtkWindow::resize-grip-width = 0\n\n\t\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\n\t\# Color/g' /usr/share/themes/Ambiance/gtk-2.0/gtkrc 

如前所述,它似乎是\ n \ n表示出现问题的原因是什么都可以更换。有什么更好的方法来做到这一点?

我在Ubuntu 11.10上,命令将从shell脚本运行而不是perl脚本。

回答

2

当您打开一个文件进行读取,该文件默认情况下逐行读取。这是因为输入记录分隔符$/设置为换行符。

既然你打破了换行符上的每一个“行”,那么理由是你永远无法在一行中找到两行换行符。

解决此问题的一种方法是,正如Zaid所说的,用-0标志更改输入记录分隔符。只要新的输入记录分隔符不与你的正则表达式部分匹配,你就会没事的。 (只要您不尝试匹配.\n)。

让我们让你的正则表达式变得不那么可怕。除非使用/x修饰符,否则不需要转义#。您不需要连续使用几个#字符,请使用量词+, * or {x,y}

除了删除一个字符串然后放回一个相同的字符串,还有一些选项可以避免两次输入相同的东西。

  • 您可以避免使用Lookaround Assertions删除字符串。
  • 您可以使用\K作为一个简化的外观,背后断言(见上文)
  • 您可以捕捉字符串,将它们放回使用$1, $2 ...

在这种情况下,我的首选是使用一个后视断言来查找“color \ n \ n”字符串,然后查找“Color”注释。

perl -0777 -pwe 's/(?<=color\n\n)(?=[#\s]+Color)/INSERT\n\n/' /path/to/file 

哪里INSERT当然是你要插入的文本,这是我的可读性删除。我还删除了-i标志,因此您可以先尝试一下。

+0

我会给你一个镜头,谢谢。我认为我需要转义所有散列,因此从shell脚本运行时不会将其解释为注释。正如你所指出的,我的解决方案是可怕的。捕捉字符串的使用更加优雅。我只有大约2天进入perl,并且有很多东西需要学习。 – Veazer 2012-01-31 16:42:25

+0

@ user30441这不是捕获,它是查找断言。在shell脚本中使用时,元字符会变得麻烦。将代码放入脚本并调用它可能会更容易。例如。 'perl/home/script.pl'。 – TLP 2012-01-31 16:48:16

+0

感谢您的澄清。我试图避免调用任何外部脚本,并且您的方法运行良好。 – Veazer 2012-01-31 17:01:02

3

您需要一次性加载整个文件以检测\n\n。使用-0777覆盖默认的行由行行为:

$ perl -0777 -pi -e 's/\n\n/TEST/g' myfile.xml 
+0

完美。感谢您快速准确的答复。我用正确的用法更新了我的问题。 – Veazer 2012-01-31 15:51:51

+0

+1虽然你在夸夸道说“你需要”。您只需使用任何其他输入记录分隔符读取文件,而不是使用单个换行符。 – TLP 2012-01-31 16:13:06

+2

您的问题经常被问到,“我在多条线路上遇到问题,出了什么问题?” http://learn.perl.org/faq/perlfaq6.html#Im-having-trouble-matching-over-more-than-one-line.-Whats-wrong- – tadmc 2012-01-31 16:16:44