【问题标题】:Swift Get string between 2 strings in a stringSwift获取字符串中2个字符串之间的字符串
【发布时间】:2015-07-30 13:41:30
【问题描述】:

我从 html 解析中得到一个字符串;

string = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"

我的代码类似于

var startIndex = text.rangeOfString("'")
var endIndex = text.rangeOfString("',")
var range2 = startIndex2...endIndex
substr= string.substringWithRange(range)

我不确定我的第二个拆分字符串应该是“'”还是“'”,

我希望我的结果是

substr = "Info/99/something"

【问题讨论】:

  • 总是有相同的长度(例如 1) - 还是不同? 'Info/..." 总是一样吗?请分享更多字符串,以找出获取字符串的最佳方法。
  • javascript:getInfo(1,'Info/123/somethingelse', 'City2 hall3',456,789);

标签: ios string swift substring


【解决方案1】:
extension String {
    
    func slice(from: String, to: String) -> String? {
        return (range(of: from)?.upperBound).flatMap { substringFrom in
            (range(of: to, range: substringFrom..<endIndex)?.lowerBound).map { substringTo in
                String(self[substringFrom..<substringTo])
            }
        }
    }
}

"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
  .sliceFrom("'", to: "',")

【讨论】:

  • 这太棒了!谢谢!
  • @oisdk 如果我们需要从一个字符串切到字符串的末尾,它会起作用吗?例如:“blabla popo titi toto”-> 切片(从“popo”,到:endOfString)?
  • 惊人而简单
  • 在 Swift 4 中,您还可以将第二个范围计算为 self[substringFrom...].range(of: to),这样可以节省一些击键和提及 endIndex
  • 我发现这个 return flatmap.().map() 代码很难理解这个函数;所以我尝试了rewriting a version using guard
【解决方案2】:

我会使用正则表达式从这样的复杂输入中提取子字符串。

斯威夫特 3.1:

let test = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"

if let match = test.range(of: "(?<=')[^']+", options: .regularExpression) {
    print(test.substring(with: match))
}

// Prints: Info/99/something

斯威夫特 2.0:

let test = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"

if let match = test.rangeOfString("(?<=')[^']+", options: .RegularExpressionSearch) {
    print(test.substringWithRange(match))
}

// Prints: Info/99/something

【讨论】:

【解决方案3】:

我重写了one of the top Swift answers 以了解它对map 的作用。我更喜欢使用guard,IMO 的版本。

extension String {
    
    func slice(from: String, to: String) -> String? {
        guard let rangeFrom = range(of: from)?.upperBound else { return nil }
        guard let rangeTo = self[rangeFrom...].range(of: to)?.lowerBound else { return nil }
        return String(self[rangeFrom..<rangeTo])
    }
    
}

行为:

let test1 =   "a[b]c".slice(from: "[", to: "]") // "b"
let test2 =     "abc".slice(from: "[", to: "]") // nil
let test3 =   "a]b[c".slice(from: "[", to: "]") // nil
let test4 = "[a[b]c]".slice(from: "[", to: "]") // "a[b"

【讨论】:

    【解决方案4】:

    查找起始字符串和结束字符串之间的所有子字符串:

    extension String {
        func sliceMultipleTimes(from: String, to: String) -> [String] {
            components(separatedBy: from).dropFirst().compactMap { sub in
                (sub.range(of: to)?.lowerBound).flatMap { endRange in
                    String(sub[sub.startIndex ..< endRange])
                }
            }
        }
    }
    
    let str = "start A end ... start B end"
    str.sliceMultipleTimes(from: "start", to: "end")    // ["A", "B"]
    

    【讨论】:

    • 谢谢,这正是我想要的
    【解决方案5】:

    如果它始终是第二个拆分,则此方法有效:

    let subString = split(string, isSeparator: "'")[1]
    

    【讨论】:

    • 让 subString = split(text, "'") ;返回子字符串[1];在此代码中,它给出错误“调用中参数“isSeparator”的参数缺失”
    【解决方案6】:

    您可以使用 var arr = str.componentsSeparatedByString(",") 作为您的第二个拆分,它将返回您的数组

    【讨论】:

    • 我在一个函数中执行此子字符串处理,当我调用 return subString[1] 时会给出错误“无法使用 () 类型的索引下标 '[String]' 类型的值。”如果我调用 subString[0] 它会按预期工作
    【解决方案7】:

    斯威夫特 4.2:

    extension String {
    
        //right is the first encountered string after left
        func between(_ left: String, _ right: String) -> String? {
            guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
                ,leftRange.upperBound <= rightRange.lowerBound else { return nil }
    
            let sub = self[leftRange.upperBound...]
            let closestToLeftRange = sub.range(of: right)!
            return String(sub[..<closestToLeftRange.lowerBound])
        }
    
    }
    

    【讨论】:

      【解决方案8】:

      考虑使用正则表达式来匹配单引号之间的所有内容。

      let string = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
      
      let pattern = "'(.+?)'"
      let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)
      let results = regex!.matchesInString(string, options: nil, range: NSMakeRange(0, count(string)))  as! [NSTextCheckingResult]
      
      let nsstring = string as NSString
      let matches = results.map { result in return nsstring.substringWithRange(result.range)}
      
      // First match
      println(matches[0])
      

      【讨论】:

        【解决方案9】:

        斯威夫特 5

        extension String {
        
            ///Returns an empty string when there is no path.
            func substring(from left: String, to right: String) -> String {
                if let match = range(of: "(?<=\(left))[^\(right)]+", options: .regularExpression) {
                    return String(self[match])
                }
                return ""
            }
        }
        

        【讨论】:

          【解决方案10】:

          在 Swift 4 或更高版本中,您也可以在 StringProtocol 上创建扩展方法来支持子字符串。你可以只返回一个Substring 而不是一个新的字符串:

          edit/u[日期:Swift 5

          extension StringProtocol  {
              func substring<S: StringProtocol>(from start: S, options: String.CompareOptions = []) -> SubSequence? {
                  guard let lower = range(of: start, options: options)?.upperBound
                  else { return nil }
                  return self[lower...]
              }
              func substring<S: StringProtocol, T: StringProtocol>(from start: S, to end: T, options: String.CompareOptions = []) -> SubSequence? {
                  guard let lower = range(of: start, options: options)?.upperBound,
                      let upper = self[lower...].range(of: end, options: options)?.lowerBound
                  else { return nil }
                  return self[lower..<upper]
              }
          }
          

          let string = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
          let substr = string.substring(from: "'")                   // "Info/99/something', 'City Hall',1, 99);"
          let subString = string.substring(from: "'", to: "',")  // "Info/99/something"
          
          let subStringCaseInsensitive = string.substring(from: "'info/", to: "/something", options: .caseInsensitive)  // "99"
          

          【讨论】:

            【解决方案11】:

            如果你想从字符串的开头或结尾也支持

            extension String {
                func slice(from: String, to: String) -> String? {
                    return (from.isEmpty ? startIndex..<startIndex : range(of: from)).flatMap { fromRange in
                        (to.isEmpty ? endIndex..<endIndex : range(of: to, range: fromRange.upperBound..<endIndex)).map({ toRange in
                            String(self[fromRange.upperBound..<toRange.lowerBound])
                        })
                    }
                }
            }
            
            "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
              .slice(from: "'", to: "',") // "Info/99/something"
            
            "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
              .slice(from: "", to: ":") // "javascript"
            
            "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
              .slice(from: ":", to: "") // "getInfo(1,'Info/99/something', 'City Hall',1, 99);"
            
            "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
              .slice(from: "", to: "") // "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
            

            如果你想要另一种语法,也许更易读

            extension String {
                func slice(from: String, to: String) -> String? {
                    guard let fromRange = from.isEmpty ? startIndex..<startIndex : range(of: from) else { return nil }
                    guard let toRange = to.isEmpty ? endIndex..<endIndex : range(of: to, range: fromRange.upperBound..<endIndex) else { return nil }
                    
                    return String(self[fromRange.upperBound..<toRange.lowerBound])
                } 
            }
            

            【讨论】:

              【解决方案12】:

              Swift 4 版本的@litso。查找文本中的所有值

              func find(inText text: String, pattern: String) -> [String]? {
                  do {
                      let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
                      let result = regex.matches(in: text, options: .init(rawValue: 0), range: NSRange(location: 0, length: text.count))
              
                      let matches = result.map { result in
                          return (text as NSString).substring(with: result.range)
                      }
              
                      return matches
                  } catch {
                      print(error)
                  }
                  return nil
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-02-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-12-28
                相关资源
                最近更新 更多