簡體   English   中英

使用<>和regex搜索和替換文本文件中的元素

[英]Using <> and regex to search and replace elements in text files

我正在通過Learning Perl ,第9章“使用正則表達式處理文本”。

這是章節結束練習中的兩個:

  1. 編寫一個程序,為目前為止的所有練習答案添加一個版權行,在'shebang'行之后立即在## Copyright (c) 20XX by Yours Truly中添加## Copyright (c) 20XX by Yours Truly 假設將使用文件名調用程序,以便在命令行上進行編輯。

  2. 修改以前的程序,使其不編輯已包含版權行的文件。 作為提示,您可能需要知道菱形運算符讀取的文件名是$ ARGV。

這是我嘗試的解決方案:

#!/usr/bin/env perl

use 5.014;
use warnings;

my $shebang     = '(#!/usr/bin/env perl|#!/usr/bin/perl)'; 
my $copyright   = '# Copyright (c) 20XX Yours Truly'; 

$^I = ".bak";

while (<>) {
    unless (/$copyright/mi) {
        s/($shebang)/$1\n$copyright/mig;
    }
    print;
}

使用perl ch9.pl sample_perl_script.pl在命令行上運行。

我的目標是:

  • 無論路徑如何,保持原始的shebang完好無損。
  • 只需一次循環<>
  • 檢查是否存在版權聲明。
  • 如果沒有,請添加它(因此嘗試unless { ... } )。

這適用於問題的第一部分(添加版權線)但不適用於第二部分(檢查以確保版權尚不存在)。

我的問題是:為什么? 為什么在我運行程序時完全忽略了unless

我偷看了附錄,本書提出的解決方案是創建一個哈希來跟蹤$ARGV文件名,並將文件傳遞兩次 首先要刪除已經有版權聲明的文件,然后執行搜索/替換。 像這樣:

my %do_these;
foreach (@ARGV) {
    $do_these{$_} = 1;
}

while (<>) { 
    if (/\A## Copyright/) {
        delete $do_these{$ARGV};
    }
}

@ARGV = sort keys %do_these; 
$^I = ".bak";
while (<>) {
    if (/\A#!/) {
        $_ .= "## Copyright (c) 20XX by Yours Truly\n";
    }
    print;
}

當然,這有效,但似乎是工作的兩倍。 我試圖通過我的方法在單個while (<>) { ... }循環中找到一種方法來實現這一點,並且更好地理解鑽石算子的工作原理。

如果我的方法完全偏離基礎,請解釋原因並且不要放過我的感受。 我對比我的自我更全面的了解更感興趣。

你的書的方法愚蠢的。 實際上,我認為perl正在bar,因為你的版權聲明有像(

你想要的是quotemeta函數。 鏈接

我會改變你的程序:

while (<>) {
    my $copyright2 = quotemeta $copyright;
    unless (/$copyright2/mi) {
        s/($shebang)/$1\n$copyright/mig;
    }
    print;
}

如果這不起作用,請道歉。 我寫perl已經有一段時間了。

你的unless不起作用,因為版權與shebang不在同一條線上。 鑽石運算符讀取一行直到$/的第一個值,默認情況下是換行符。 您的程序將在不包含版權的所有上執行替換。

由於這是perl,因此有很多方法可以解決它。 最直接的方法可能是取消設置$/並啜飲文件(將其全部讀成一行)。 這樣,如果文件的第二行有版權聲明,您可以立即查看。 例如:

local $/;                                     # slurp the file
while (<>) {
    s/^.*\n\K(?!\Q$copyright\E)/$copyright/;  # negative lookahead assertion
    print;
}

您還可以直接在文件中檢查第2行,而不會詆毀文件:

while (<>) {
    if ($. == 2) {
         unless (/\Q$copyright/) {
               print "$copyright\n";
         }
    }
    print;
    close ARGV if eof;                # this will reset the line counter $.
}

請注意,Nick ODell是正確的,您的版權字符串包含必須轉義的元字符(即括號)。 我在上面使用了\\Q ... \\E轉義序列。

另請注意,您不需要非常具體地檢查shebang,這更有可能在稍微不同的線路上絆倒您。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM