2012-11-21 56 views
0

我想創建一個RegEx,查找以單引號或雙引號開頭和結尾的字符串。Preg模式,忽略轉義字符

例如,我可以像本場比賽這樣的情況:

String: "Hello World" 
RegEx: /[\"\'][^\"\']+[\"\']/ 

但是,出現問題時的報價出現字符串本身像這樣:

String: "Hello" World" 

我們知道上面的表達式會不行。

我希望能夠做的,它有字符串本身內逃生,因爲這無論如何都會被要求的功能:

String: "Hello\" World" 

現在我能拿出一個長期而複雜的表達一組以各種模式,其中之一是:

RegEx: /[\"\'][^\"\']+(\\\"|\\\')+[^\"\']+[\"\']/ 

但是這對我似乎過高,我認爲有可能是一個更短,更優雅的解決方案。

預期語法:

run arg1 "arg1" "arg3 with \"" "\"arg4" "arg\"\"5" 

正如你所看到的,報價實際上只用於確保該字符串用空格算作一個字符串。不要擔心arg1,我應該可以匹配未加引號的參數。

我會讓這更容易,參數只能用雙引號括起來。所以我已經從這個問題的要求中拿出了單引號。

我已經修改瑞Jarimba的例子:

/(?<=")(\\")*([^"]+((\\(\"))*[^"])+)((\\"")|")/ 

這已經佔到相當不錯大多數情況下,但有一個可以打敗這個最後一種情況:

run -a "arg3 \" p2" "\"sa\"mple\"\\" 

第二個參數結束與\\"這是一種傳統的方法在這種情況下,允許在嵌套字符串的末尾反斜槓,不幸的是,正則表達式認爲這是一個轉義報價,因爲模式\"仍然存在於最後的模式。

+0

劇本應該知道什麼是引用來改變的,巫婆可以算作開始/結束參數的基礎是什麼? – Peon

+0

根據外部引號,是的,一個更大的字符串可以包含更多的引用嵌套字符串,因此reg ex必須能夠找到它們全部。如果嵌套字符串用單引號封裝,則任何內部雙引號不需要轉義,反之亦然。 – Flosculus

+0

所以你正在尋找'第一'和'最後'引號之間的所有文本? – Peon

回答

1

試試這個正則表達式:

['"]([^'"]+((\\(\"|'))*[^'"])+)['"] 

考慮以下字符串:

"Hello" World 'match 2' "wqwqwqwq wwqwqqwqw" no match here oopop "Hello \" World" 

它將匹配

"Hello" 
'match 2' 
"wqwqwqwq wwqwqqwqw" 
"Hello \" World" 
+0

修復了正則表達式。PS:我使用.NET正則表達式進行測試,但它應該可以和PHP一起工作 –

+0

你的轉義是不一致的(你只能轉義雙引號一次),否則它應該工作(除了不區分兩個分隔符的可能性) –

+0

這也是固定的。現在它正在處理超過1個轉義報價 –

4

首先,請使用'字符串來編寫正則表達式。這可以爲您節省大量的轉義。

然後我看到兩種可能性。你的嘗試的問題是,它只允許在字符串中的一個地方連續轉義引號。而且,這允許在開始和結束時使用不同的引號。你可以使用反向引用來解決這個問題。因此,這將是a)稍微更優雅和b)更正:

$pattern = '/(["\'])(\\"|\\\'|[^"\'])+\1/'; 

請注意,交替的順序很重要!

問題在於,您不希望轉義您不用於分隔字符串的引號。因此,另一種可能性是使用lookarounds(因爲反向引用不能字符類內使用):

$pattern = '/(["\'])(?:(?!\1).|(?<=\\\\)\1)+\1/'; 

注意,四個連續反斜線總是需要匹配單個反斜槓。這是因爲在實際字符串$pattern中,它們最終爲\\,然後正則表達式引擎「使用」第一個字符串以逃避第二個字符串。

這將匹配任意字符,如果它是而不是的起始引號。或者如果前一個字符是反斜槓,它將匹配起始報價。

Working demo.

這的方式等同於:

$pattern = '/(["\'])(?:\\\\\1|(?!\1).)+\1/'; 

但在這裏,你再次寫入順序交替。

Working demo.

最後一個音符。您可以通過分成兩個可能的字符串(單,雙引號中的字符串)避免反向引用:

$pattern = '/"(?:\\\\"|[^"])+"|\'(?:\\\\\'|[^\'])+\'/'; 

但是你說你要找的東西短典雅;)(不過,這最後一個可能是更有效率...但你必須描述它)。

請注意,我所有的正則表達式都留有一個未考慮的案例:引用字符串外部的轉義引號。即Hello \" World "Hello" World會給你" World"。你能避免這一點使用另一個負回顧後(使用作爲一個例子,我提供一個工作演示的第二個正則表達式,它會工作同所有其他人):

$pattern = '/(?<!\\\\)(["\'])(?:\\\\\1|(?!\1).)+\1/'; 
+0

以下看不到這個下降的人我在說'在另一個問題的回合。如果你暗示我是那個人,我必須說我不是。事實上,我upvoted你的答案。 – Carlos

+0

@jackflash否我並沒有暗示這一點,我剛剛看到了你的回答,最近我的表現很不理想,也從來沒有解釋過,所以我只想表達我對你和你的仇恨者的同情心, –

+0

哦,好吧!我認識的人只是爲我們有一天的爭論而低估了它。 – Carlos