Swift 4.2 извлекает подстроку с использованием нескольких символов-разделителей - PullRequest
0 голосов
/ 26 ноября 2018

Я новичок в Swift, и после просмотра документации Apple и других источников мне не ясно, как мне извлечь подстроку, используя более одного символа в качестве разделителя.Например: у меня есть строка, которая выглядит следующим образом:

A.1 value1 B.2 value2 E value3 C value4

, и мне необходимо присвоить значения 1 - 4 различным переменным.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Мне нравятся регулярные выражения для такого рода вещей.

Я собираюсь взять вас буквально и предположить, что найденным подстрокам предшествуют "A.1", "B.2", "E"и "C", и перед ними стоит пробел, за которым следует пробел, за исключением последней подстроки, за которой следует конец исходной строки.Более того, я собираюсь очень просто предположить, что такие разделители, как "E", не могут появляться в нашей строке любым другим способом.Затем мы можем захватить каждую подстроку с соответствующим шаблоном:

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"]

. Однако я должен указать на другой способ сделать эту сортировкудело в том, чтобы пройти оригинальную строку со сканером.Вы можете предпочесть это, потому что регулярные выражения здесь на самом деле не нужны, и если вы не знаете регулярные выражения, вы найдете этот способ обхода намного более понятным.Так что здесь переписано использование сканера.Обратите внимание, что в итоге мы имеем четыре необязательных объекта 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
0 голосов
/ 27 ноября 2018

• Возможное решение:
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"]

Вдохновение для 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"

Вы хотите «значение одно», и, так как есть пробел, вы получите некоторую проблему, потому что если выдаст ложный результат (так какесть разделитель).Вы получите: ["A.1": "value", "One": "B.2", "value2": "E", "value3": "C"] для 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

Обратите внимание, что триммер может быть внутри регулярного выражения, ноМне не особенно нравятся слишком сложные регулярные выражения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...