2016-03-16 39 views
1

我有follwing模式匹配一個正則表達式在TCL PERL

Pattern[1]: 
    Key : "key1" 
    Value : 100 
    Pattern[2]: 
    Key : "key2" 
    Value : 20 
    Pattern[3]: 
    Key : "key3" 
    Value : 30 
    Pattern[4]: 
    Key : "key4" 
    Value : 220 

我想每個隔離塊Pattern。我正在使用TCL。正則表達式,我使用是不解析目的

set updateList [regexp -all -inline {Pattern\[\d+\].*?Value.*?\n} $list] 

這正則表達式用來分隔每個模式

我需要爲

Pattern[1]: 
    Key : "key1" 
    Value : 100 


    Pattern[2]: 
    Key : "key2" 
    Value : 20 


    Pattern[3]: 
    Key : "key3" 
    Value : 30 


    Pattern[4]: 
    Key : "key4" 
    Value : 220 
+0

也許,'模式\ [\ d + \]:\ S *鍵* \ S *值*' –

+0

@WiktorStribiżew:。這是不working – Nitesh

+1

'set updateList [regexp -all -inline {Pattern \ [[0-9] + \]:\ s * Key [^ \ n] * \ s * Value [^ \ n] *} $ str]'is 。一個點與Tcl中的換行符相匹配,這就是爲什麼上面那個不起作用。 –

回答

2

你的模式Pattern\[\d+\].*?Value.*?\n包含混合量詞:既貪婪又懶惰。 Tcl並不像您期望的那樣處理混合量詞類型,例如PCRE(PHP,Perl),.NET等,它默認爲第一個找到的類型,因爲隨後的量詞繼承了前面的量詞類型。所以,\d之後的+是貪婪的,因此,所有其他人(在.*?中)也是貪婪的 - 即使你宣稱它們是懶惰的。此外,.也與Tcl正則表達式中的換行符匹配,因此,您的模式的工作方式與this類似。

所以,根據你的正則表達式,你可以使\d+慵懶\d+?,並在與(?:\n|$)末取代\n同時匹配換行和字符串的結尾:

set RE {Pattern\[\d+?\].*?Value.*?(?:\n|$)} 
set updateList [regexp -all -inline $RE $str] 

IDEONE demo

替代1

此外,您還可以使用更詳細的正則表達式,如果你輸入的字符串始終具有相同的結構與所有元素 - PatternKeyValue - 至今:

set updateList [regexp -all -inline {Pattern\[\d+\]:\s*Key[^\n]*\s*Value[^\n]*} $str] 

IDEONE demo,這裏是regex demo

由於.可以匹配一個換行符,因此我們需要使用一個[^\n]否定字符類來匹配除換行符之外的任何字符。

替代2

您可以使用展開懶子模式匹配Pattern[n]:,然後任何字符,這並不是一個Pattern[n]:序列的起點:

set RE {Pattern\[\d+\]:[^P]*(?:P(?!attern\[\d+\]).)*} 
set updateList [regexp -all -inline $RE $str] 

another IDEONE demoregex101 demo

+0

下面是[另一個更簡短的演示](https://ideone.com/O1INgr)證明了我的觀點,關於你的正則表達式中懶惰到貪婪的「轉換」:'\ d + [a-zA -Z] +?\ d +?'應該匹配'56gddd666'中的'56gddd6',但它匹配整個字符串,因爲最後一個'\ d +?'實際上是作爲一個貪婪子模式(它從[[a -Za-Z] +?'這是一個貪婪的子模式,因爲它從第一個'\ d +'繼承了這種行爲)。 –

+0

關於模式的貪婪選擇的好解釋。因此,將'\ d +'改爲'\ d +?'將適用於OP,因爲所有其他量詞也不是非貪婪的。 –

+0

@glennjackman:我也想過,但還有一點需要注意:最後一項沒有跟着一個換行符。一個替代組是必要的。 –

1

輸出試試這個

Pattern\[\d+\](.|\n)*?Value.*?\n 

的點字符匹配任何字符,但斷行,所以你需要將其添加到。要知道,你的行可能以回車字符結束,所以你可能需要在加\ r

+0

不工作。它不是隔離模式 – Nitesh

1

你想要捕捉線條塊,並輸出它們之間的空行。您的示例數據顯示不同級別的模式,可用於識別哪些線路屬於哪個模塊。

最簡單的模式是:輸入中的每三行組成一個塊。此模式建議如下處理:

set lines [split [string trim $list \n] \n] 
foreach {a b c} $lines {puts $a\n$b\n$c\n\n} 

示例數據中沒有任何內容表明這不起作用。不過,您的示例數據中可能會有一些併發症未反映出來。

如果有輸入流浪空行,你可能需要得到第一個擺脫他們:

set lines [lmap line $lines {if {[string is space $line]} continue else {set line}}] 

如果某些塊包含更少或更多的線比你的榜樣,另一個簡單的模式是,每塊以具有可選(?)空格和單詞Pattern的行開始。這些線路(除第一)應當由輸出塊分隔符前面:

set lines [split [string trim $list \n] \n] 
puts [lindex $lines 0] 
foreach line [lrange $lines 1 end] { 
    if {[regexp {\s*Pattern} $line]} { 
     puts \n$line 
    } else { 
     puts $line 
    } 
} 
puts \n 

如果線實際上並不空白開始,你可以使用string match Pattern* $line而不是正則表達式。

文檔:continueforeachiflindexlmaplmap更換,lrangeputsregexpsetsplitstring

+0

我喜歡它。您假設(合理)鍵值中沒有換行符,或任何「意外」空白行。 –

+0

添加有關此代碼如何回答問題的解釋將改善您對未來訪問者的回答(此答案被標記爲低質量)。 – JAL

1
% set list { Pattern[1]: 
    Key : "key1" 
    Value : 100 
    Pattern[2]: 
    Key : "key2" 
    Value : 20 
    Pattern[3]: 
    Key : "key3" 
    Value : 30 
    Pattern[4]: 
    Key : "key4" 
    Value : 220 
} 
% regexp -all -inline {Pattern\[\d+\].*?Value.*?\n} $list 
{Pattern[1]: 
    Key : "key1" 
    Value : 100 
    Pattern[2]: 
    Key : "key2" 
    Value : 20 
    Pattern[3]: 
    Key : "key3" 
    Value : 30 
    Pattern[4]: 
    Key : "key4" 
    Value : 220 
} 
% regexp -all -inline {Pattern\[\d+?\].*?Value.*?\n} $list ;# only changing `\d+` to `\d+?` 
{Pattern[1]: 
    Key : "key1" 
    Value : 100 
} {Pattern[2]: 
    Key : "key2" 
    Value : 20 
} {Pattern[3]: 
    Key : "key3" 
    Value : 30 
} {Pattern[4]: 
    Key : "key4" 
    Value : 220 
} 

如果$列表確實末以新行,你將不會得到返回的「pattern [4]」元素。在這種情況下,改變

% regexp -all -inline {Pattern\[\d+?\].*?Value.*?\n} $list 

% regexp -all -inline {Pattern\[\d+?\].*?Value.*?(?:\n|$)} $list