Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios NSRegularExpression中的命名捕获组-获取范围';s组';姓名_Ios_Regex_Nsregularexpression_Icu - Fatal编程技术网

Ios NSRegularExpression中的命名捕获组-获取范围';s组';姓名

Ios NSRegularExpression中的命名捕获组-获取范围';s组';姓名,ios,regex,nsregularexpression,icu,Ios,Regex,Nsregularexpression,Icu,苹果称NSRegularExpression基于ICU正则表达式库: 当前支持的模式语法是由ICU指定的。有关ICU正则表达式的说明,请参阅 该页面(在icu project.org上)声称现在支持命名捕获组,使用与.NET正则表达式相同的语法: (?…)命名的捕获组。是文字-它们出现在模式中 我已经编写了一个程序,它可以获得一个与多个范围的匹配,这似乎是正确的-尽管每个范围返回两次(原因未知)-但我唯一掌握的信息是范围的索引及其文本范围 例如,正则表达式:^(?foo)\.(?bar)\.(?

苹果称NSRegularExpression基于ICU正则表达式库:

当前支持的模式语法是由ICU指定的。有关ICU正则表达式的说明,请参阅

该页面(在icu project.org上)声称现在支持命名捕获组,使用与.NET正则表达式相同的语法:

(?…)
命名的捕获组。
是文字-它们出现在模式中

我已经编写了一个程序,它可以获得一个与多个范围的匹配,这似乎是正确的-尽管每个范围返回两次(原因未知)-但我唯一掌握的信息是范围的索引及其文本范围

例如,正则表达式:
^(?foo)\.(?bar)\.(?baz)$
带有测试字符串
foo.bar.baz

给我这些结果:

Idx    Start    Length     Text
0      0        11         foo.bar.baz
1      0         3         foo
2      4         3         bar
3      8         3         baz

有没有办法知道“
baz
”来自捕获组
bar2

我也面临同样的问题,最终支持了我自己的解决方案。请随意评论或改进;-)

扩展名NSRegularExpression{ typealias GroupNamesSearchResult=(NSTextCheckingResult,NSTextCheckingResult,Int) private func textCheckingResultsOfNamedCaptureGroups()抛出->[字符串:GroupNamesSearchResult]{ var groupnames=[String:GroupNamesSearchResult]() 让greg=尝试NSRegularExpression(模式:“^\\(\\?.\\)$”,选项:NSRegularExpressionOptions.DotMatchesLineSeparators) let reg=尝试NSRegularExpression(模式:“\\([^\\(\\)]*\\”,选项:NSRegularExpressionOptions.DotMatchesLineSeparators) 设m=reg.matchesInstalling(self.pattern,选项:NSMatchingOptions.WithTransparentBounds,范围:NSRange(位置:0,长度:self.pattern.utf16.count)) 对于m.enumerate()中的(n,g){ 让gstring=self.pattern.substringWithRange(g.rangeAtIndex(0.toRange()!) 打印(self.pattern.substringWithRange(g.rangeAtIndex(0.toRange()!)) 设gmatch=greg.matcheInstalling(gstring,选项:NSMatchingOptions.archored,范围:NSRange(位置:0,长度:gstring.utf16.count)) 如果gmatch.count>0{ GroupName[gstring.substringWithRange(gmatch[0].RangeAtinex(1).toRange()!)]=(g,gmatch[0],n) } } 返回组名 } func indexOfNamedCaptureGroups()抛出->[字符串:Int]{ var groupnames=[String:Int]() 对于try self.textCheckingResultsOfNamedCaptureGroups()中的(name,(,,,n)){ 组名[名称]=n+1 } //打印(组名) 返回组名 } func rangesOfNamedCaptureGroups(匹配:NSTextCheckingResult)抛出->[字符串:范围]{ 变量范围=[字符串:范围]() 对于try self.textCheckingResultsOfNamedCaptureGroups()中的(name,(,,,n)){ ranges[name]=match.rangeAtIndex(n+1).toRange() } 返回范围 } } 下面是一个使用示例:

let node = "'test_literal'"
let regex = try NSRegularExpression(pattern: "^(?<delimiter>'|\")(?<value>.*)(?:\\k<delimiter>)$", options: NSRegularExpressionOptions.DotMatchesLineSeparators)
let match = regex.matchesInString(node, options: NSMatchingOptions.Anchored, range: NSRange(location: 0,length: node.utf16.count))
if match.count > 0 {

    let ranges = try regex.rangesOfNamedCaptureGroups(match[0])
    guard let range = ranges["value"] else {

    }
}
let node=“'test_literal'”
让regex=try NSRegularExpression(模式:“^(?“\”)(?:\\k)$”,选项:NSRegularExpressionOptions.DotMatchesLineSeparators)
让match=regex.matcheInstalling(节点,选项:NSMatchingOptions.archored,范围:NSRange(位置:0,长度:node.utf16.count))
如果match.count>0{
let ranges=尝试regex.rangesOfNamedCaptureGroups(匹配[0])
防护等级范围=范围[“值”]其他{
}
}

我已经完成了创建的示例

有许多变化:

  • 首先,代码现在与Swift 3兼容
  • Daniele的代码有一个缺陷,它不会捕获嵌套的捕获。我已经使正则表达式稍微不那么激进,以允许捕获组嵌套
  • 我更喜欢在一个集合中实际接收捕获。我添加了一个名为
    captureGroups()
    的方法,该方法将捕获作为字符串而不是范围返回

    import Foundation
    
    extension String {
        func matchingStrings(regex: String) -> [[String]] {
            guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
            let nsString = self as NSString
            let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
            return results.map { result in
                (0..<result.numberOfRanges).map { result.rangeAt($0).location != NSNotFound
                    ? nsString.substring(with: result.rangeAt($0))
                    : ""
                }
            }
        }
    
        func range(from nsRange: NSRange) -> Range<String.Index>? {
            guard
                let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
                let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex),
                let from = from16.samePosition(in: self),
                let to = to16.samePosition(in: self)
                else { return nil }
            return from ..< to
        }
    
    }
    
    extension NSRegularExpression {
        typealias GroupNamesSearchResult = (NSTextCheckingResult, NSTextCheckingResult, Int)
    
        private func textCheckingResultsOfNamedCaptureGroups() -> [String:GroupNamesSearchResult] {
            var groupnames = [String:GroupNamesSearchResult]()
    
            guard let greg = try? NSRegularExpression(pattern: "^\\(\\?<([\\w\\a_-]*)>$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else {
                // This never happens but the alternative is to make this method throwing
                return groupnames
            }
            guard let reg = try? NSRegularExpression(pattern: "\\(.*?>", options: NSRegularExpression.Options.dotMatchesLineSeparators) else {
                // This never happens but the alternative is to make this method throwing
                return groupnames
            }
            let m = reg.matches(in: self.pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: self.pattern.utf16.count))
            for (n,g) in m.enumerated() {
                let r = self.pattern.range(from: g.rangeAt(0))
                let gstring = self.pattern.substring(with: r!)
                let gmatch = greg.matches(in: gstring, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: gstring.utf16.count))
                if gmatch.count > 0{
                    let r2 = gstring.range(from: gmatch[0].rangeAt(1))!
                    groupnames[gstring.substring(with: r2)] = (g, gmatch[0],n)
                }
    
            }
            return groupnames
        }
    
        func indexOfNamedCaptureGroups() throws -> [String:Int] {
            var groupnames = [String:Int]()
            for (name,(_,_,n)) in try self.textCheckingResultsOfNamedCaptureGroups() {
                groupnames[name] = n + 1
            }
            return groupnames
        }
    
        func rangesOfNamedCaptureGroups(match:NSTextCheckingResult) throws -> [String:Range<Int>] {
            var ranges = [String:Range<Int>]()
            for (name,(_,_,n)) in try self.textCheckingResultsOfNamedCaptureGroups() {
                ranges[name] = match.rangeAt(n+1).toRange()
            }
            return ranges
        }
    
        private func nameForIndex(_ index: Int, from: [String:GroupNamesSearchResult]) -> String? {
            for (name,(_,_,n)) in from {
                if (n + 1) == index {
                    return name
                }
            }
            return nil
        }
    
        func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = []) -> [String:String] {
            return captureGroups(string: string, options: options, range: NSRange(location: 0, length: string.utf16.count))
        }
    
        func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [String:String] {
            var dict = [String:String]()
            let matchResult = matches(in: string, options: options, range: range)
            let names = try self.textCheckingResultsOfNamedCaptureGroups()
            for (n,m) in matchResult.enumerated() {
                for i in (0..<m.numberOfRanges) {
                    let r2 = string.range(from: m.rangeAt(i))!
                    let g = string.substring(with: r2)
                    if let name = nameForIndex(i, from: names) {
                        dict[name] = g
                    }
                }
            }
            return dict
        }
    }
    
    它将打印:


    [“分隔符”:“\”,“全部”:“\'test\u literal\”,“值”:“test\u literal”]

    因为支持iOS11命名捕获组。
    NSTextCheckingResult
    具有此功能


    将正则表达式:
    ^(?foo)\.(?bar)\.(?baz)$
    与测试字符串
    foo.bar.baz
    一起使用,将给出4个结果匹配。函数
    match.range(名称为:“bar2”)
    返回字符串的范围
    baz

    您查看了吗?@Thomas我确实看到了,但是从2014年开始,讨论都说不支持命名捕获组-但是(至少在iOS 9和OS X 10.11上)do似乎是受支持的-而且他们在我的机器上工作,至少,我无法从结果范围映射回他们来自的组。而iOS 4.0和更高版本中可用的Apple doc状态…@Thomas文档指出,
    NSRegularExpression
    类是添加到iOS 4.0的,而不是对命名Captur的支持e组是在iOS 4.0中添加的。@Thomas事实上,苹果自己的
    NSRegularExpression
    文档中没有列出命名捕获组的语法,它只出现在ICU自己的文档中,表明命名捕获组是最近添加的。很有趣!您能用一些用法示例修改您的答案吗?完成。在ta之后再看一眼,我也意识到这并不明显……几个月前我写了这段代码,有理由在两个单独的调用中进行匹配和范围。谢谢,你救了我。我基于此编写了一个扩展,用所有命名的捕获组及其值创建一个字典:
    import Foundation
    
    extension String {
        func matchingStrings(regex: String) -> [[String]] {
            guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
            let nsString = self as NSString
            let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
            return results.map { result in
                (0..<result.numberOfRanges).map { result.rangeAt($0).location != NSNotFound
                    ? nsString.substring(with: result.rangeAt($0))
                    : ""
                }
            }
        }
    
        func range(from nsRange: NSRange) -> Range<String.Index>? {
            guard
                let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
                let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex),
                let from = from16.samePosition(in: self),
                let to = to16.samePosition(in: self)
                else { return nil }
            return from ..< to
        }
    
    }
    
    extension NSRegularExpression {
        typealias GroupNamesSearchResult = (NSTextCheckingResult, NSTextCheckingResult, Int)
    
        private func textCheckingResultsOfNamedCaptureGroups() -> [String:GroupNamesSearchResult] {
            var groupnames = [String:GroupNamesSearchResult]()
    
            guard let greg = try? NSRegularExpression(pattern: "^\\(\\?<([\\w\\a_-]*)>$", options: NSRegularExpression.Options.dotMatchesLineSeparators) else {
                // This never happens but the alternative is to make this method throwing
                return groupnames
            }
            guard let reg = try? NSRegularExpression(pattern: "\\(.*?>", options: NSRegularExpression.Options.dotMatchesLineSeparators) else {
                // This never happens but the alternative is to make this method throwing
                return groupnames
            }
            let m = reg.matches(in: self.pattern, options: NSRegularExpression.MatchingOptions.withTransparentBounds, range: NSRange(location: 0, length: self.pattern.utf16.count))
            for (n,g) in m.enumerated() {
                let r = self.pattern.range(from: g.rangeAt(0))
                let gstring = self.pattern.substring(with: r!)
                let gmatch = greg.matches(in: gstring, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: gstring.utf16.count))
                if gmatch.count > 0{
                    let r2 = gstring.range(from: gmatch[0].rangeAt(1))!
                    groupnames[gstring.substring(with: r2)] = (g, gmatch[0],n)
                }
    
            }
            return groupnames
        }
    
        func indexOfNamedCaptureGroups() throws -> [String:Int] {
            var groupnames = [String:Int]()
            for (name,(_,_,n)) in try self.textCheckingResultsOfNamedCaptureGroups() {
                groupnames[name] = n + 1
            }
            return groupnames
        }
    
        func rangesOfNamedCaptureGroups(match:NSTextCheckingResult) throws -> [String:Range<Int>] {
            var ranges = [String:Range<Int>]()
            for (name,(_,_,n)) in try self.textCheckingResultsOfNamedCaptureGroups() {
                ranges[name] = match.rangeAt(n+1).toRange()
            }
            return ranges
        }
    
        private func nameForIndex(_ index: Int, from: [String:GroupNamesSearchResult]) -> String? {
            for (name,(_,_,n)) in from {
                if (n + 1) == index {
                    return name
                }
            }
            return nil
        }
    
        func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = []) -> [String:String] {
            return captureGroups(string: string, options: options, range: NSRange(location: 0, length: string.utf16.count))
        }
    
        func captureGroups(string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [String:String] {
            var dict = [String:String]()
            let matchResult = matches(in: string, options: options, range: range)
            let names = try self.textCheckingResultsOfNamedCaptureGroups()
            for (n,m) in matchResult.enumerated() {
                for i in (0..<m.numberOfRanges) {
                    let r2 = string.range(from: m.rangeAt(i))!
                    let g = string.substring(with: r2)
                    if let name = nameForIndex(i, from: names) {
                        dict[name] = g
                    }
                }
            }
            return dict
        }
    }
    
        let node = "'test_literal'"
        let regex = try NSRegularExpression(pattern: "^(?<all>(?<delimiter>'|\")(?<value>.*)(?:\\k<delimiter>))$", options: NSRegularExpression.Options.dotMatchesLineSeparators)
        let match2 = regex.captureGroups(string: node, options: NSRegularExpression.MatchingOptions.anchored)
        print(match2)