我感到羞愧,但我仍然不清楚正則表達式的一些方面。 我需要解析文本文件,其中包含一些@"I'm a string"
格式的字符串文字。 我已經組成了簡單的模式/@"([^"]*)"/si
。它工作完美,preg_match_all返回一個集合。但是,如果字符串文字包含像@"I'm plain string. I'm \"qouted\" string "
這樣的轉義引號,顯然它不能正常工作。將不勝感激任何線索。Assism with regexp
回答
這是一個用例Freidl的經典作品「展開循環」:(編輯固定捕獲分組)
/"((?:[^"\\]|\\.)*)"/
這將匹配引用字符串,以反斜槓轉義引號考慮。
你可以使用匹配字段(包括@
)的完整的regex是:
/@"((?:[^"\\]|\\.)*)"/
但要小心!我經常看到有人抱怨說這種模式在PHP中不起作用,這是因爲在字符串中使用了反斜槓的略微融化的性質。
上述模式中的反斜槓代表文字需要傳遞到PCRE的反斜槓。這意味着,他們需要在PHP字符串中使用時,他們是兩次轉義:
$expr = '/@"((?:[^"\\\\]|\\\\.)*)"/';
preg_match_all($expr, $subject, $matches);
print_r($matches[1]); // this will show the content of all the matched fields
它是如何工作的?
...我聽到你問。那麼,讓我們看看我能否以一種真正有意義的方式解釋這一點。讓我們使x
模式,這樣我們就可以空出來了一下:
/
@ # literal @
" # literal "
( # start capture group, we want everything between the quotes
(?: # start non-capturing group (a group we can safely repeat)
[^"\\] # match any character that's not a " or a \
| # ...or...
\\. # a literal \ followed by any character
)* # close non-capturing group and allow zero or more occurrences
) # close the capture group
" # literal "
/x
這真的很重要的點是這些:
[^"\\]|\\.
- 意味着每一個反斜槓是「平衡」 - 每一個反斜槓必須轉義字符,並且不會有一次以上的角色被考慮。- 將
*
包裹在上面的重複組意味着上述模式可以發生無限次數,並且允許空字符串(如果您不想允許空字符串,請將*
更改爲+
)。這是「展開循環」的「循環」部分。
但輸出字符串仍然包含逃脫引號的反斜線?
確實如此,這只是一個匹配程序,它不會修改匹配。但是因爲結果是字符串的內容,所以簡單的str_replace('\\"', '"', $result)
將是安全的並且產生正確的結果。
但是,做這樣的事情的時候,我經常發現我要處理其他轉義序列,以及 - 在這種情況下,我通常會做這樣的事情的結果:
preg_replace_callback('/\\./', function($match) {
switch ($match[0][1]) { // inspect the escaped character
case 'r':
return "\r";
case 'n':
return "\n";
case 't':
return "\t";
case '\\':
return '\\';
case '"':
return '"';
default: // if it's not a valid escape sequence, treat the \ as literal
return $match[0];
}
}, $result);
這使得類似的行爲轉換爲PHP中的雙引號字符串,其中\t
被選項卡替換,\n
被替換爲換行符等。
如果我想允許單引號字符串呢?
這已經給我很長時間了。我一直有這樣一種微妙的感覺,認爲這可以通過反向引用更有效地處理,但許多嘗試未能產生任何可行的結果。
我這樣做:
/(?:"((?:[^"\\]|\\.)*)")|(?:'((?:[^'\\]|\\.)*)')/
正如你所看到的,這基本上是採用基本相同的圖案兩次,OR關係。該字符串的提取在PHP端略微複雜,以及:
$expr = '/(?:"((?:[^"\\\\]|\\\\.)*)")|(?:\'((?:[^\'\\\\]|\\\\.)*)\')/';
preg_match_all($expr, $subject, $matches);
$result = array();
for ($i = 0; isset($matches[0][$i]); $i++) {
if ($matches[1][$i] !== '') {
$result[] = $matches[1][$i];
} else {
$result[] = $matches[2][$i];
}
}
print_r($result);
Where '\\。'會傾斜像\ t,\'\ n'等任何奇怪的斜線轉義+1 – 2013-03-19 12:23:09
@Allendar這樣做的好處是,它只會在非轉義的雙引號,任何其他反斜槓組合逃生將保持不變。我會盡力以可理解的方式分解它是如何工作的。 – DaveRandom 2013-03-19 12:29:20
謝謝,你讓我的一天,戴夫!非捕獲組正是我正在尋找的,這是錯過了我的正則表達式知識的一部分 – heximal 2013-03-19 13:57:26
您需要使用負回顧後 - 直到你找到一個報價沒有反斜槓匹配的一切。這是Java:
public static void main(String[] args) {
final String[] strings = new String[]{"@\"I'm a string\"", "@\"I'm plain string. I'm \\\"qouted\\\" \""};
final Pattern p = Pattern.compile("@\"(.*)\"(?<!\\\\)");
System.out.println(p.pattern());
for (final String string : strings) {
final Matcher matcher = p.matcher(string);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
}
}
輸出:
I'm a string
I'm plain string. I'm \"qouted\"
模式(沒有所有的Java逃逸)是:@"(.*)"(?<!\\)
是不是要求PHP的問題? – 2013-03-19 12:23:41
正則表達式是正確的嗎?正則表達式模式的作品,OP只需要轉義任何需要在PHP中轉義的需求。 – 2013-03-19 12:24:55
PHP Regex實際上有不同的規則,需要額外的轉義引號。除此之外,它可能會讓提問人員疑惑他/她是否缺乏JAVA的知識,即使這對我們大多數人來說也是有意義的;通常不會假設它是如此。你的正則表達式本身是正確的:) – 2013-03-19 12:26:50
- 1. RegExp
- 2. RegExp在@
- 3. RegExp在
- 4. 使用RegExp選擇範圍
- 5. Ruby和RegExp
- 6. JavaScript RegExp問題
- 7. MYSQL REGEXP搜索
- 8. Regexp Javascript替換
- 9. REGEXP在Android SQLite
- 10. regexp匹配xxx.xxx.xxx?
- 11. typescript import {RegExp}
- 12. Java RegExp ViewState
- 13. 使用REGEXP
- 14. JavaScript RegExp對象
- 15. JavaScript RegExp替換
- 16. Ruby + JSON + Regexp
- 17. MYSQL使用REGEXP
- 18. Python中的RegExp
- 19. Regexp援助
- 20. REGEXP替換/%
- 21. Flash RegExp問題
- 22. PHP RegExp替換
- 23. Grep/RegExp幫助
- 24. RegExp混淆
- 25. Object with Combobox with With語句
- 26. emacs regexp用「11」取代11
- 27. SQL WITH WITH
- 28. MySql REGEXP運算符
- 29. 問題RegExp和IE
- 30. 瞭解emacs align-regexp
其實我想你的轉義字符串和模式似乎工作 – aleation 2013-03-19 12:15:02
是,該模式起作用,但由佔位符([^「] *)佔用的值不如預期的那樣 – heximal 2013-03-19 12:18:55
'preg_match_all('/@"(.*)"$/ si',$ text,$ match);'。?? – MatRt 2013-03-19 12:20:28