[英]Pattern matching with regex on article reference
我需要在PHP中模式匹配給定字符串中的許多文章引用,然后我想要提取它們。 引用最多可包含16位數字,每個數字可以具有不同的值。 有一點要知道:從數字11開始(包括數字11),輸入數據中的所有內容都是可選的(但是如果你在可選數字之后有一些有效的東西,那么這個數字必然是“ - ”)。 此外,如果直到結尾都有“ - ”,則可以截斷引用。 例如 :
A2 - L3500XM -----可以是A2 - L3500XM
D4 - L4652Z-4 ----可以是D4 - L4652Z-4
A3 - L5020MW4 --- A保持A3 - L5020MW4 --- A.
這些都是有效的參考。 這是我到目前為止所做的工作:
[DA][1-5][V\-][AN\-][LMFGHN][\d]{4}[H-RT-ZBD]([H-RT-ZBD\-]?)(?(-1)[1-4\-]?)
我達到了第11位,但這就是它變得棘手的地方。 這是我的示例參考:
D1--L6000T-4 VALID D1--L6000T VALID D1--L6000T4----- INVALID D1--L6000T----- VALID
我用VALID注釋了應該匹配的那些。 我的問題是我的正則表達式采用了所有這些(按預期截斷“ - ”),但第三個不應該匹配,因為4對第11位無效。 我認為它確實采用4的原因是因為第10位是可選的,這意味着如果它不在那里我猜-1可能是指[H-RT-ZBD] ,它包含幾乎相同的字符? 所以我在這里有點迷失,我的問題是:我怎樣才能做到這一點? 有更容易的方法嗎 ? 甚至可以做到嗎?
模式規則:
digit number : pattern
1 : [DA]
2 : [1-5]
3 : [V-]
4 : [AN-]
5 : [LMFGHN]
6-9 : \d{4}
10 : [H-RT-ZBD]
11 : [H-RT-ZBD-]?
12 : [1-4-]?
13 : [KRX-]?
14 : [CPW-]?
15 : [MT-]?
16 : [A-C-]?
通常,要匹配的輸入字符串是具有大量空格和可能的任何字符的普通表。
以下正則表達式對您提供的所有規則和輸入的評估結果為true。 您可以復制整個塊並使用它,包括注釋。
$string = "D1--L6000T4------ A3--L5020MW4---A D4--L4652Z-4---- D1--L6000T";
preg_match_all(
'/( # Matching the start of the group
[DA] # Digit 1
[1-5] # Digit 2
[V-] # Digit 3
[AN-] # Digit 4
[LMFGHN] # Digit 5
\d{4} # Digit 6-9
[H-RT-ZBD] # Digit 10
(?:[H-RT-ZBD-] # Digit 11
(?:[1-4-] # Digit 12
(?:[KRX-] # Digit 13
(?:[CPW-] # Digit 14
(?:[MT-] # Digit 15
[A-C-] # Digit 16
?)?)?)?)?)?) # Closing all the groups and alternations
(?:(?=(\s|%20))|$ # Matching a space (even %20) or end of string. This is done to exclude partial matches.
)/x',
$string, $matches
);
var_dump($matches);
關於我改變了什么的幾點說明。
刪除了字符組內的短划線的轉義。 如果它被放置在不標記間隔的地方,它將像任何其他角色一樣。
刪除了\\d
周圍的字符組[ ]
。
我沒有將第11個數字作為可選項,而是寫出模式與11和out的不同之處。 組的遞歸可選性確保如果第12個字符能夠匹配,則需要第11個字符,依此類推。
結束邊界
我已經將(?:(?=(\\s|%20))|$
到正則表達式的末尾,這樣可以確保只有在沒有后續字符的情況下才會匹配此模式。這樣做是折扣部分匹配的唯一方法,例如D1--L6000T
中的D1--L6000T4------
當你不能保證每個模式都用空格分隔時。坦率地說我覺得很奇怪。
檢索比賽
構造正則表達式使得完整模式可用作匹配部分,或匹配數組中的索引0。
我猜-1可以引用
[H-RT-ZBD]
,它包含幾乎相同的字符?
不,它確實是指([H-RT-ZBD\\-]?)
,這是最后一個捕獲組。 然而,它始終匹配,因為字母是可選的 - 然后捕獲空字符串。 你的條件是真的。
我猜你應該選擇你的角色捕捉組,而不是捕捉一個可選角色(參見http://www.regular-expressions.info/captureall.html的差異)。 所以試試吧
[DA][1-5][V-][AN-][LMFGHN]\d{4}[H-RT-ZBD]([H-RT-ZBD-])?(?(-1)([1-4-]))?(?(-1)([KRX-]))?(?(-1)([CPW-]))?(?(-1)([MT-]))?(?(-1)[A-C-])?
如果您不需要捕獲組,則可以使用更自然的嵌套而不是條件來簡化表達式:
[DA][1-5][V-][AN-][LMFGHN]\d{4}[H-RT-ZBD](?:[H-RT-ZBD-](?:[1-4-](?:[KRX-](?:[CPW-](?:[MT-][A-C-]?)?)?)?)?)?
當然,你必須在任何情況下錨定你的表達式,以便與無效輸入的有效子部分匹配:-)你可以將它包裝在^
+ $
, (?<!\\S)
+ (?!\\S)
或(?<=\\s|^)
+ (?=\\s|$)
。
您應該僅使用正則表達式來選擇可能的模式,以便從原始字符串中提取它們。
獲得所選潛在模式的數組后,使用IF
和SWITCH
語句以及substr
和其他字符串比較函數來確定每個模式是否有效。
否則,您可能會編寫過於復雜的正則表達式,這些正則表達式需要花費很長時間才能進行調試,而且更新時間太長而且沒有人會想要在之后使
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.