[英]Ruby Regex: Capture the same capture groups multiple times
我在我們的身份驗證系統中有這些字符串,我正在嘗試開發正確的 REGEX 以從中捕獲特定信息。
STRING = CR*reduced*downsized*U*reduced*D*own_only
現在我需要能夠提取第一個捕獲組中的大寫字母(如 CRUD),以及緊隨其后的星號所包含的“屬性”(例如downsized )。 對於大多數使用以下 REGEX 的情況,這非常有效
(C)\*?([a-z_]+)?\*? --> Capture Group 1: "C", Capture Group2: empty
(U)\*?([a-z_]+)?\*? --> Capture Group 1: "U", Capture Group2: 'reduced'
(C)\*?([a-z_]+)?\*? --> Capture Group 1: "D", Capture Group2: 'own_only'
對於 R,我需要返回這兩個屬性,因此 Capture Group2 應該是“reduced”,Capture Group3 應該是“downsized”。 但是使用相同的正則表達式,我只得到以下結果
(R)\*?([a-z_]+)?\*? --> Capture Group 1: "R", Capture Group2: 'reduced'
關於正則表達式的任何建議?
由於這是一個涉及重復捕獲組的場景,您可以使用像這樣的多步驟解決方案
text = 'CR*reduced*downsized*U*reduced*D*own_only'
rx = /([CRUD])((?:\*[a-z_]+(?:\*[a-z_]+)*(?:\*|$))?)/
matches = text.scan(rx)
p matches.map { |x| [x[0], x[1].split("*").reject(&:empty?)]};
# => [["C", []], ["R", ["reduced", "downsized"]], ["U", ["reduced"]], ["D", ["own_only"]]]
詳情:
([CRUD])
- 第 1 組:4 個字母之一((?:\*[a-z_]+(?:\*[a-z_]+)*(?:\*|$))?)
- 第 2 組:可選序列
\*
- *
字符[a-z_]+
- 一個或多個 ASCII 小寫字母或下划線(?:\*[a-z_]+)*
- 零個或多個*
序列和一個或多個 ASCII 小寫字母或下划線(?:\*|$)
- *
或一行的結尾(使用\z
匹配整個字符串的結尾)。 使用.map { |x| [x[0], x[1].split("*").reject(&:empty?)]}
.map { |x| [x[0], x[1].split("*").reject(&:empty?)]}
,你可以用*
拆分第二組值並刪除空項。
提取所需信息的一種方法如下。
def breakup(str)
str.scan(/[A-Z][a-z_*]*/).map { |s| [s[0], s.scan(/[a-z_]+/)]}
end
相應的正則表達式為“匹配一個大寫字母后跟零個或多個(最后的‘*’)小寫字母、下划線和星號”和“匹配一個或多個(‘+’)小寫字母和下划線”。
str1 = "CR*reduced*downsized*U*reduced*D*own_only"
breakup(str1)
#=> [["C", []], ["R", ["reduced", "downsized"]], ["U", ["reduced"]],
# ["D", ["own_only"]]]
str2 = "CR*reduced*downsized*U*reduced*DE"
breakup(str2)
#=> [["C", []], ["R", ["reduced", "downsized"]], ["U", ["reduced"]],
# ["D", []], ["E", []]]
注意
str1.scan(/[A-Z][a-z_*]*/)
#=> ["C", "R*reduced*downsized*", "U*reduced*", "D*own_only"]
如果有必要測試字符串是否具有有效的構造,可以嘗試將其與以下正則表達式進行匹配(我已經以自由間距模式表示以使其自我記錄)。
RGX =
/
\A # match beginning of the string
(?: # begin a non-capture group
[A-Z] # match one upcase letter
(?: # begin a non-capture group
(?: # begin a non-capture group
\* # match '*'
[a-z_]+ # match one or more of the characters indicated
)+ # end non-capture group and execute one or more times
(?: # begin a non-capture group
\* # match '*'
(?=[A-Z]) # pos lookahead asserts next char is an upcase letter
| # or
\z # at end of string
) # end non-capture group
)? # end non-capture group and optionally match it
)+ # end non-capture group and execute it one or more times
\z # match end of string
/x # invoke free-spacing regex definition mode
str3 = "CR*reduced*downsizedU*reduced*D*own_only"
str4 = "CR*reduced*downsized*U*reduced*D*own_only*"
str5 = "*CR*reduced*downsized*U*reduced*D*own_only"
[str1, str2, str3, str4, str5].map { |s| valid?(s) }
#=> [true, true, false, false, false]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.