![](/img/trans.png)
[英]How to Parse and Combine More than 10 RSS Feed into one array using Swift on iOS
[英]How to capture more than 10 things using Swift 5.7's RegexBuilder?
假設我有一個存儲有關人員信息的文件,其中一行如下所示:
Sweeper 30 1992-09-22 China/Beijing - 0 2020-07-07 Mary/Linda - Pizza/Lemon
從左到右依次為姓名、年齡、出生日期、出生國家、出生城市、子女數量、結婚日期(可選)、妻子姓名(可選)、前妻姓名(可選)、喜歡的食物、最不喜歡的食物。
我想使用 Swift 5.7 RegexBuilder 模塊從行中獲取所有信息,我嘗試過:
let regex = Regex {
/([a-zA-Z ]+)/ // Name
" "
TryCapture { OneOrMore(.digit) } transform: { Int($0) } // Age
" "
Capture(.iso8601Date(timeZone: .gmt)) // Date of Birth
" "
/([a-zA-Z ]+)/ // Country of Birth
"/"
/([a-zA-Z ]+)/ // City of Birth
" - "
TryCapture { OneOrMore(.digit) } transform: { Int($0) } // Children Count
Optionally {
" "
Capture(.iso8601Date(timeZone: .gmt)) // Date of Marriage
Optionally {
" "
/([a-zA-Z ]+)/ // Wife
Optionally {
"/"
/([a-zA-Z ]+)/ // Ex-wife
}
}
}
" - "
/([a-zA-Z ]+)/ // Favourite food
"/"
/([a-zA-Z ]+)/ // Least Favourite Food
}
但是,Swift 表示無法在合理的時間內進行類型檢查。
我知道發生這種情況的原因是因為RegexComponentBuilder
(正則表達式組件的結果生成器)僅具有最多 10 個“C”或類似內容的重載(對細節不太確定):
static func buildPartialBlock<W0, W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, R0, R1>(
accumulated: R0,
next: R1) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0 : RegexComponent, R1 : RegexComponent, R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9, C10
)
如果我將所有Optionally
部分都設置為required ,則錯誤消息會變得更加明顯。
'buildPartialBlock(accumulated:next:)' 的模糊使用
SwiftUI 也有類似的問題,視圖構建器中的視圖數量不能超過 10,在這種情況下,您只需使用Group
將某些視圖變成單個視圖。 你能在 RegexBuilder 中做類似的事情嗎? 使某些捕獲成為一次捕獲? 它似乎與AnyRegexOutput
,但我不確定如何使用它。
如何解決此編譯器錯誤?
為避免 XY 問題:
我有一個數據文件,其中數據的格式非常隨意,即根本不像 CSV 或 JSON 那樣機器可讀。 行以各種格式編寫。 隨機分隔符用於隨機位置。
然后文件中的另一行將具有相同的信息,但以不同的方式格式化。
我想做的是將這個格式怪異的文件轉換為易於使用的格式,例如 CSV。 我決定使用 Swift 5.7 RegexBuilder API 來執行此操作。 我會在文件中找到一行,編寫一個與該行匹配的正則表達式,將文件中與該正則表達式匹配的所有行轉換為 CSV,然后沖洗並重復。
因此,我想避免使用多個正則表達式來解析一行,因為這意味着我將編寫更多的正則表達式。
我不確定像 ANTLR4 這樣的解析器是否能解決我的問題。 鑒於文件格式的隨機性,我需要大量更改解析器,導致文件一次又一次地生成。 我認為這不會像使用 RegexBuilder 那樣方便。
作為 hack ,您可以創建一個通用的CustomConsumingRegexComponent
實現,它接受
RegexComponent
,它始終具有(Substring, A, B, C...)
元組為 outputT
的轉換我們基本上可以創建一個正則表達式組件,它接受一些正則表達式並輸出我們想要的任何類型T
,本質上是“分組”捕獲。
也可以不進行轉換,最終得到嵌套元組,但我不喜歡這樣。
struct Group<RegexOutput, Component: RegexComponent>: CustomConsumingRegexComponent {
let component: () -> Component
let transform: (Component.RegexOutput) -> RegexOutput
init(@RegexComponentBuilder _ regexBuilder: @escaping () -> Component, transform: @escaping (Component.RegexOutput) -> RegexOutput) {
component = regexBuilder
self.transform = transform
}
func consuming(_ input: String, startingAt index: String.Index, in bounds: Range<String.Index>) throws -> (upperBound: String.Index, output: RegexOutput)? {
let innerRegex = Regex(component)
guard let match = input[index...].prefixMatch(of: innerRegex) else { return nil }
let upperBound = match.range.upperBound
let output = match.output
let transformedOutput = transform(output)
return (upperBound, transformedOutput)
}
}
之所以這只是一個 hack,是因為Group
內部的正則表達式實際上並不知道Group
之外的東西,所以Group
內部的量詞不會回溯以嘗試匹配Group
之外的東西。
例如,要修復問題中的代碼,我可以將所有與婚姻相關的信息放入一個Group
中,但我必須在Group
中添加一個前瞻:
struct Marriage {
let marriageDate: Date
let wife: Substring?
let exWife: Substring?
}
let r = Regex {
/([a-zA-Z ]+)/ // Name
" "
TryCapture { OneOrMore(.digit) } transform: { Int($0) } // Age
" "
Capture(.iso8601Date(timeZone: .gmt)) // Date of Birth
" "
/([a-zA-Z ]+)/ // Country of Birth
"/"
/([a-zA-Z ]+)/ // City of Birth
" - "
TryCapture { OneOrMore(.digit) } transform: { Int($0) } // Children Count
Optionally {
" "
Capture(Group {
Capture(.iso8601Date(timeZone: .gmt)) // Date of Marriage
Optionally {
" "
/([a-zA-Z ]+)/ // Wife
Optionally {
"/"
/([a-zA-Z ]+)/ // Ex-wife
}
}
Lookahead(" - ")
} transform: { (_, date, wife, exWife) in
Marriage(marriageDate: date, wife: wife, exWife: exWife as? Substring) // unwrap the double optional
})
}
" - "
/([a-zA-Z ]+)/ // Favourite food
"/"
/([a-zA-Z ]+)/ // Least Favourite Food
}
如果沒有前瞻,會發生以下情況:
最里面[a-zA-Z ]+
將匹配Linda
,以及它后面的空格,導致" - "
不匹配。 通常情況下,這會導致回溯,但是由於Group
內部的東西不知道Group
外部的東西,所以這里不會發生回溯,整個匹配失敗。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.