【问题标题】:Swift 4.2 extract substring using multiple characters are delimiterSwift 4.2 使用多个字符提取子字符串是分隔符
【发布时间】:2019-04-27 21:29:00
【问题描述】:

我是 Swift 新手,在浏览了 Apple 文档和其他来源后,我不清楚如何使用多个字符作为分隔符来提取子字符串。例如:我有一个字符串,看起来像:

A.1 值1 B.2 值2 E值3 C值4

并且需要将值 1 - 4 分配给不同的变量。

【问题讨论】:

  • 你是什么意思“将值 1 - 4 分配给不同的变量”,你能举个例子吗?
  • 你需要使用Regular Expressions从字符串中提取这些
  • 还提供什么字符串模式可以用作分隔符...
  • 分配值 1 - 4 不明确。你的意思是 1 - 4 还是 value1 - value4
  • 抱歉含糊不清。我的目标是提取 A.1 和 B.2 之间的字符串,并在 E 和 C 之间创建一个变量,如 name = value1,并创建变量 surname = value3。唯一的常量是字段 ID:A.1、B.2、E、C

标签: ios swift string


【解决方案1】:

• 可能的解决方案:
1. 分隔所有元素(分隔符:空格)
2. 2 2 迭代并使用键/值系统,例如Dictionary
3. 之后从键中读取每个值

第 1 步:

let string = "A.1 value1 B.2 value2 E value3 C value4"
let components = string.components(separatedBy: CharacterSet.whitespaces)

第 2 步:

var dictionary: [String: String] = [:]
stride(from: 0, to: components.count - 1, by: 2).forEach({ 
    dictionary[components[$0]] = components[$0+1]
})

let dictionary = stride(from: 0, to: components.count - 1, by: 2).reduce(into: [String: String]()) { (result, currentInt) in 
    result[components[currentInt]] = components[currentInt+1]
}

dictionary["A.1": "value1", "C": "value4", "E": "value3", "B.2": "value2"]

Inspiration 表示我很少使用的stride(from:to:)

第 3 步:

let name = dictionary["A.1"]
let surname = dictionary["C"]

• 潜在问题:
如果你有:

let string = "A.1 value One B.2 value2 E value3 C value4"

你想要“value One”,因为有一个空格,你会遇到一些问题,因为 if 会给出错误的结果(因为有分隔符)。 你会得到: ["A.1": "value", "One": "B.2", "value2": "E", "value3": "C"] for dictionary

因此您可以使用正则表达式:A.1(.*)B.2(.*)E(.*)C(.*)(例如)。

let string = "A.1 value One B.2 value2 E value3 C value4"
let regex = try! NSRegularExpression(pattern: "A.1(.*)B.2(.*)E(.*)C(.*)", options: [])

regex.enumerateMatches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) { (result, flags, stop) in
    guard let result = result,
          let aValueRange = Range(result.range(at: 1), in: string),
          let bValueRange = Range(result.range(at: 2), in: string),
          let cValueRange = Range(result.range(at: 4), in: string),
          let eValueRange = Range(result.range(at: 3), in: string) else { return }
    let aValue = string[aValueRange].trimmingCharacters(in: CharacterSet.whitespaces)
    print("aValue: \(aValue)")
    let bValue = string[bValueRange].trimmingCharacters(in: CharacterSet.whitespaces)
    print("bValue: \(bValue)")
    let cValue = string[cValueRange].trimmingCharacters(in: CharacterSet.whitespaces)
    print("cValue: \(cValue)")
    let eValue = string[eValueRange].trimmingCharacters(in: CharacterSet.whitespaces)
    print("eValue: \(eValue)")

}

输出:

$>aValue: value One
$>bValue: value2
$>cValue: value4
$>eValue: value3

请注意,修剪可能在正则表达式内,但我不特别喜欢过于复杂的正则表达式。

【讨论】:

    【解决方案2】:

    我喜欢这类事情的正则表达式。

    我会按照字面意思告诉你,假设要找到的子字符串前面有"A.1""B.2""E""C",并且前面和后面都有一个空格,除了对于最后一个子字符串,后面跟着原始字符串的结尾。此外,我将非常简单地假设"E" 之类的分隔符不能以任何other 方式出现在我们的字符串中。然后我们可以用适当的模式捕获每个子字符串:

    let s = "A.1 harpo B.2 chico E zeppo C groucho"
    let p1 = "^A\\.1 (.*) B\\.2 "
    let p2 = " B\\.2 (.*) E "
    let p3 = " E (.*) C "
    let p4 = " C (.*)$"
    let patts = [p1,p2,p3,p4]
    var result = [String]()
    for patt in patts {
        let regex = try! NSRegularExpression(pattern: patt, options: [])
        if let match = regex.firstMatch(in: s, options: [], 
            range: NSRange(s.startIndex..<s.endIndex, in: s)) {
                let r = match.range(at: 1)
                result.append((s as NSString).substring(with: r))
        }
    }
    // result is now ["harpo", "chico", "zeppo", "groucho"]
    

    我们现在将四个所需的子字符串提取到一个数组中,从那里处理它们很简单。

    请注意,我们没有对空间做出任何假设。即使目标子字符串包含空格,上述方法也能很好地工作,因为我们只对分隔符有吸引力。例如,如果原始字符串是

    let s = "A.1 the rain B.2 in spain E stays mainly C in the plain"
    

    那么result就是数组

    ["the rain", "in spain", "stays mainly", "in the plain"]
    

    然而,我应该指出,做这种事情的另一种方法是 walk 使用 Scanner 原始字符串。你可能更喜欢这个,因为这里真的不需要正则表达式,如果你不知道正则表达式,你会发现这种走得更清楚。所以这里改写为使用扫描仪。请注意,我们最终得到了四个 Optional NSString 对象,因为 Scanner 实际上是一个 Objective-C Cocoa Foundation 的东西,但根据需要将它们转换为 String 对象并不难:

    let s = "A.1 the rain B.2 in spain E stays mainly C in the plain"
    let scan = Scanner(string: s)
    scan.scanString("A.1 ", into: nil)
    var r1 : NSString? = nil
    scan.scanUpTo(" B.2 ", into: &r1)
    scan.scanString("B.2 ", into: nil)
    var r2 : NSString? = nil
    scan.scanUpTo(" E ", into: &r2)
    scan.scanString("E ", into: nil)
    var r3 : NSString? = nil
    scan.scanUpTo(" C ", into: &r3)
    scan.scanString("C ", into: nil)
    var r4 : NSString? = 
        (scan.string as NSString).substring(from: scan.scanLocation) as NSString
    r1 // the rain
    r2 // in spain
    r3 // stays mainly
    r4 // in the plain
    

    【讨论】:

      猜你喜欢
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 2018-02-05
      • 2014-01-05
      • 2011-12-26
      • 2015-12-28
      • 1970-01-01
      • 2017-06-27
      相关资源
      最近更新 更多