2008-10-24 31 views
1

我可能這樣做都是錯誤的。我有一個文本文件充滿了數據,我想匹配和替換文件中的「項目」和「目錄號碼」的模式。但是文件中每個元素的順序都非常重要,所以我想從文件頂部開始匹配/替換,然後按照我的方式工作。如何讓我的正則表達式匹配第一個模式而不是最後一個?

下面的代碼片段實際上可以工作,但是當我執行它時,它將替換「SeaMonkey」的第三個實例&「SMKY-1978」模式,然後它將替換該模式的第二個實例。我想要做的是替換模式的第一個實例,然後替換第二個。

所以希望我的輸出地說「找到Kurt的 SMKY 1978年SeaMonkeys」,然後「找到Shane的 SMKY 1978年SeaMonkeys」,然後離開米克的SMKY 1978年SeaMonkeys孤單,因爲我只是想找到並替換模式的前兩個實例。現在它說「找到Shane的 SMKY-1978 SeaMonkeys」和「Found Mick的 SMKY-1978 SeaMonkeys」,因爲它每次執行for循環時都匹配最後一個模式。

所以我錯過了一個微妙的小已知正則表達式字符,或者我只是做我想做的完全和完全錯誤?

這裏是工作代碼:

# my regexp matches from the bottom to the top but I'd like it to replace from the top down 
local $/=undef; 
my $DataToParse = <DATA>; 
my $item = "SeaMonkeys"; 
my $catNum = "SMKY-1978"; 
my $maxInstancesToReplace = 2; 
parseData(); 
exit(); 

sub parseData { 
    for (my $counter = 0; $counter < $maxInstancesToReplace; $counter++) { 
     # Stick in a temporary text placeholder that I will replace later after more processing 
     $DataToParse =~ s/(.+)\sELEMENT\s(.+?)\s\(Item := \"$item\".+?CatalogNumber := \"$catNum.+?END_ELEMENT(.+)/$1 ***** Found $2\'s $catNum $item. (counter: $counter) *****$3/s; 
    } 
    print("Here's the result:\n$DataToParse\n"); 
} 

__DATA__ 
    ELEMENT Kurt (Item := "BrightLite", 
        ItemID := 29, 
        CatalogNumber := "BTLT-9274", 
        Vendor := 100, 
    END_ELEMENT 

    ELEMENT Mick (Item := "PetRock", 
        ItemID := 36, 
        CatalogNumber := "PTRK-3475/A", 
        Vendor := 82, 
    END_ELEMENT 

    ELEMENT Kurt (Item := "SeaMonkeys", 
        ItemID := 12, 
        CatalogNumber := "SMKY-1978/E", 
        Vendor := 77, 
    END_ELEMENT 

    ELEMENT Joe (Item := "Pong", 
       ItemID := 24, 
       CatalogNumber := "PONG-1482", 
       Vendor := 5, 
    END_ELEMENT 

    ELEMENT Shane (Item := "SeaMonkeys", 
        ItemID := 1032, 
        CatalogNumber := "SMKY-1978/E", 
        Vendor := 77, 
    END_ELEMENT 

    ELEMENT Kurt (Item := "Battleship", 
        ItemID := 99, 
        CatalogNumber := "BTLS-5234", 
        Vendor := 529, 
    END_ELEMENT 

    ELEMENT Mick (Item := "SeaMonkeys", 
        ItemID := 8, 
        CatalogNumber := "SMKY-1978/F", 
        Vendor := 77, 
    END_ELEMENT 

    ELEMENT Frank (Item := "PetRock", 
        ItemID := 42, 
        CatalogNumber := "PTRK-3475/B", 
        Vendor := 82, 
    END_ELEMENT 

    ELEMENT Joe (Item := "SeaMonkeys", 
       ItemID := 8, 
       CatalogNumber := "SMKY-1979/A", 
       Vendor := 77, 
    END_ELEMENT 

而且這裏是它目前輸出:

Here's the result: 
     ELEMENT Kurt (Item := "BrightLite", 
         ItemID := 29, 
         CatalogNumber := "BTLT-9274", 
         Vendor := 100, 
     END_ELEMENT 

     ELEMENT Mick (Item := "PetRock", 
         ItemID := 36, 
         CatalogNumber := "PTRK-3475/A", 
         Vendor := 82, 
     END_ELEMENT 

     ELEMENT Kurt (Item := "SeaMonkeys", 
         ItemID := 12, 
         CatalogNumber := "SMKY-1978/E", 
         Vendor := 77, 
     END_ELEMENT 

     ELEMENT Joe (Item := "Pong", 
        ItemID := 24, 
        CatalogNumber := "PONG-1482", 
        Vendor := 5, 
     END_ELEMENT 

***** Found Shane's SMKY-1978 SeaMonkeys. (counter: 1) ***** 

     ELEMENT Kurt (Item := "Battleship", 
         ItemID := 99, 
         CatalogNumber := "BTLS-5234", 
         Vendor := 529, 
     END_ELEMENT 

***** Found Mick's SMKY-1978 SeaMonkeys. (counter: 0) ***** 

     ELEMENT Frank (Item := "PetRock", 
         ItemID := 42, 
         CatalogNumber := "PTRK-3475/B", 
         Vendor := 82, 
     END_ELEMENT 

     ELEMENT Joe (Item := "SeaMonkeys", 
        ItemID := 8, 
        CatalogNumber := "SMKY-1979/A", 
        Vendor := 77, 
     END_ELEMENT
+0

下面的答案指出這是[在其他地方發佈](http://perlmonks.org/?node_id=719433)。這很有幫助,但不屬於答案,所以我會看看是否可以刪除。 – halfer 2015-08-07 23:07:52

回答

-1

最好的解決辦法似乎是抓住從數據和正則表達式僅一個部分中的每個元... END_ELEMENT部在一個時間,而不是饋送整個完整的內容設置爲一個正則表達式一次。不完全是我想要完成的,但是我重寫了我的程序來完成這個零碎的處理過程,它像一個魅力一樣工作。

11

+在您的正則表達式的開始是 「貪婪」。這意味着它將匹配最大字符。

您正則表達式是最好寫的(這將是更具可讀性和更快)作爲

my $re=qr/\sELEMENT\s(.+?)\s\(Item := "$item".+?CatalogNumber := "$catNum.+?END_ELEMENT/; 

我認爲,你可以簡單地重複這種搭配:

sub parseData { 
    my $re=qr/\sELEMENT\s(.+?)\s\(Item := "$item".+?CatalogNumber := "$catNum.+?END_ELEMENT(.+)/; 
    foreach my $counter (0..$maxInstancesToReplace) { 
     # Stick in a temporary text placeholder that I will replace later after more processing 
     $DataToParse =~ s/$re/ ***** Found $1\'s $catNum $item. (counter: $counter) *****$2/s; 
    } 
    print("Here's the result:\n$DataToParse\n"); 
} 

如果重複是不可能的,你應該使用/ e正則表達式修飾符。

+0

我嘗試了這個答案中的代碼,它看起來不匹配數據集中的任何東西。我試圖逃避你的雙引號和其他一些事情,沒有運氣。請在發佈前測試您的答案。 – 2008-10-25 18:40:30

相關問題