2013-10-03 17 views
7

引述perlvar

...的$/的值是一個字符串,而不是一個正則表達式。 awk必須是更好的東西。 :-)

不難想象這種功能會有用的情況 - 解析具有可變長度記錄的文件是我經常遇到的經典用例。

到目前爲止,我從未有過的麻煩加載整個文件到內存中,並做了:

my @records = split /my_regex/, <> ; 

但顯而易見的原因,這種技術不能在可用內存不足的情況下使用。事實上,很多時候並不需要同時存儲所有記錄。

這使我回$/

我覺得很奇怪,語言已經不是置備$/正則表達式的支持。這是由設計完成的嗎?這是不可能實現的嗎?存在哪些其他措施可以被認爲是在沒有什麼會是一個漂亮的功能最佳做法?

+1

['Acme :: InputRecordSeparatorIsRegexp'](https://metacpan.org/pod/Acme::InputRecordSeparatorIsRegexp) – mob

+1

@mob:你不能讓awk擺脫它,現在,你能嗎? :) – Zaid

回答

8

它沒有多大意義,甚至嘗試。很多時候,如果你沒有閱讀到最後,你就無法判斷你是否已經達到了最後。在交互式情況下,這可能非常糟糕。

例如,假設您有以下程序:

local $/ = qr/\n|\r\n?/; # Handle Windows, Unix and old MacOS line endings. 
while (1) { 
    print "Please enter a command: "; 
    my $cmd = <>; 
    $cmd =~ s{$/\z}{}; 
    process($cmd); 
} 

看起來很簡單,對不對?實際上,支持qr/\n|\r\n?/可能是此請求的首要原因。那麼,即使這個簡單的代碼是嚴重的缺陷。比方說,我使用的MacOS行結尾(CR,^ M,\ r)的

$ processor 
Please enter a command: foo^M 
[hangs] 

程序掛起,因爲它不能告訴我是否給了它一個MacOS的行結尾(CR,^ M,\ R)或一個Windows行結束符(CRLF,^ M^J,\ r \ n)直到輸入另一個字符。

我不得不進入第二個命令來處理第一,第三命令處理第二,等它只是沒有任何意義。

0

Perl6::Slurp好像可以workaraound:

您可以設置輸入記錄分隔符({IRS => $ your_irs_here})爲 輸入操作。分離器可以被指定爲一個字符串或一 正則表達式。

+1

從文檔:「需要注意的是一個明確的輸入記錄分隔在一個標量上下文中沒有輸入終止效果;啜整個輸入流中總是讀,無論‘國稅局’值」 – Zaid

+0

...所以這根本就是加載在內存中的整個文件,然後分離 – Zaid

4

一個我能看到的最大問題是,在一般支持正則表達式的記錄分隔需要文件的全部內容進行掃描。

例如,假設您出於某種原因指定了一個分隔符/\n[^X]+\z/。整個文件需要被讀取以檢查是否有每個換行符後的任何字符X

所以有一些我能想到的三個選項:

  • 緩衝整個文件只掃描記錄分隔

  • 上的「分頁」字符串實現正則表達式,以便該文件可以在零件中讀取

  • 實現用作記錄分隔符的標準正則表達式的子集

從實現的角度來看,這些都不是特別有吸引力的前景,而且我可以看到,如果可能的話,我會避免這樣做,尤其是通過使用split,第一個選項可用於Perl編碼器。

+1

,人們可以提供正則表達式是沒有意義不是理由不支持正則表達式的事實。 – ikegami

+0

Re「緩衝整個文件只是爲了掃描記錄分隔符」,這已經是這種情況了(用'local $ /;'和一個不包含'$ /'的文件) – ikegami

3

Perl正則表達式引擎的(回溯)實現基本上與作爲行結尾的用法不兼容。這個問題的一部分是,當下一個字符被讀取時,你不想重新運行整個正則表達式。例如,以正則表達式

$/ = qr/ A \w*? B | XY/; 

而且數據流

f o o A 1 2 X Y B b a r 

所以應該在什麼時候readline回報?如果我們做增量匹配,我們可以得到這樣的

f o o A 1 2 X Y B b a r 
     A\w\w\w\w B 

#=> fooA12XYB 

如果我們重新運行在每個位置上全部正則表達式,我們得到

f o o A 1 2 X Y B b a r 

     A *FAIL 
     *FAIL 

     A\w *FAIL 
     *FAIL 

     A\w\w *FAIL 
     *FAIL 

     A\w\w\w *FAIL 
      X *FAIL 

     A\w\w\w\w *FAIL 
      X Y 

#=> fooA12XY 

換句話說,交替(與優先順序)使這匹配複雜。如果正則表達式引擎沒有回溯(但寧願運行爲表分析器或狀態機),就可以重新運行整個正則表達式,或者做增量匹配之間沒有什麼區別。然而,這是可能的正則表達式引擎不如Perl正則表達式。

另一個問題是結束

$/ = qr/ .+ /xs; 

應該讀這樣的「線」只返回下一個字符(因爲正則表達式一個字符之後已經滿足)的線,或整個文件(因爲.*希望儘可能匹配)?還是應該返回內部緩衝區的其餘部分,無論它當前包含什麼?

要使用正則表達式的行結束,這些模糊必須不客氣,並附加限制必須徵收(例如允許只有正規語言)。

+0

我明白了。這也回答了爲什麼awk可以做到而Perl不能做到的後續問題。 – Zaid

+0

事實上,你可以使用低效的正則表達式不是一個非常有說服力的理由不支持它們。 – ikegami

+0

'$/= qr /。+/xs;'沒有問題(除非這樣做是愚蠢的)。你必須繼續閱讀,即使沒有正則表達式。例如考慮'$/=「\ r \ n」;'或'$/= $ mime_sep;'。 – ikegami