如何在 Swift 中使用正则表达式来捕获冒号之间的字符串

How to use regex in Swift to capture string between colons

有一些任意长度的字符串 return 从后端编辑为 "junkasdojf :text:"

我如何使用正则表达式 return 一个干净的字符串作为 ":text:"(必须包含冒号)

最好是一种快速处理此问题的方法。之前没有使用过正则表达式,但我读到它是解决这个问题的唯一方法,除了进行令人讨厌的拆分和重建。

这是我目前的情况,但不确定如何取得进展

let regex = try? NSRegularExpression(pattern: ":[a-z]:", options: .caseInsensitive)

使用range(of:options:)会更简单。

let someStr = "junkasdojf :text:"
if let substrRange = someStr.range(of: ":[a-zA-Z]+:", options: .regularExpression) {
    print("Match = \(someStr[substrRange])")
} else {
    print("No match")
}

以下将匹配多次出现

// \w matches any word character such as [a-zA-Z0-9_]
let regex = try! NSRegularExpression(pattern: ":\w+:")

let nsString: NSString = "junkasdojf :text: flkasdj junkasdojf :two:"
let matches = regex.matches(in: nsString as String, options: [], range: NSMakeRange(0, nsString.length))
for match in matches {
    print(nsString.substring(with: match.range))
}

更通用的方法是使用捕获组:

let pattern = "junkasdojf\s*(:[^:]*:)"

示例 Swift 代码:

let str = "Some string here, junkasdojf :text: and more here"
let pattern = "junkasdojf\s*(:[^:]*:)"
do {
    let regex = try NSRegularExpression(pattern: pattern)
    if let match = regex.firstMatch(in: str, range: NSRange(str.startIndex..., in: str)) {
        let result = str[Range(match.range(at: 1), in: str)!]
        print(String(result))
    }
} catch { print(error) }

参见 the regex demo

在这里,junkasdojf 匹配您需要的字符串的左侧上下文子字符串,\s* 匹配 0+ 个空格,(:[^:]*:) 将冒号捕获到组 1 中, : 以外的任何 0+ 个字符,然后是 :.

或者,如果 junkasdojf: 之间的空格数不能超过某个最大阈值,您可以使用基于 constrained-width lookbehind解决方案:

let s = "Some string here, junkasdojf :text: and more here"
if let rng = s.range(of: ":(?<=junkasdojf\s{0,1000}:)[^:]*:", options: .regularExpression) {
    print(s[rng])
}

这在 regex101 上不起作用,因为它不支持 ICU 正则表达式风格,但这假设 junkasdojf 和下一个 : 之间的空格不能超过 1000 个。 :(?<=junkasdojf\s{0,1000}:)[^:]*: 匹配 :,然后确保 junkasdojf 后跟 0 到 1000 个空格和 :(这是锚定到第一个 : 所必需的) ) 然后 [^:]* 匹配 : 以外的零个或多个字符,然后 : 匹配 :.

此外,如果您对可能的最短正则表达式感兴趣但效率较低的解决方案,您可以使用

正则表达式替换输入字符串
let s = "Some string here, junkasdojf :text: and more here"
let result = s.replacingOccurrences(of: "(?s).*junkasdojf\s*(:[^:]*:).*", with: "", options: .regularExpression, range: nil)
print(result) 

输出::text:.

regex demo

详情

  • (?s) - 允许 . 匹配换行字符
  • 的修饰符
  • .* - 任何 0+ 个字符尽可能多
  • junkasdojf - 一个子字符串
  • \s* - 0+ 个空格
  • (:[^:]*:) - 捕获组 1 (</code>):冒号、除 <code>:、冒号
  • 以外的 0 个或更多字符
  • .* - 任何 0+ 个字符尽可能多

rmaddy 的答案对于一个简单的、非重复的任务来说是一个更好的方法,当你不介意在 Swift 代码中使用 NSString 时,AamirR 的答案似乎是正确的解决方案。

但是 NSRegularExpression 和 Swift String 的基本用法是这样的:

let str = "junkasdojf :text:"

//You can use `try!` when you are sure your pattern is valid.
//And do not miss `+` after `[a-z]`.
let regex = try! NSRegularExpression(pattern: ":[a-z]+:", options: .caseInsensitive)
//Use `str.utf16.count`, not `str.count`.
if let match = regex.firstMatch(in: str, range: NSRange(0..<str.utf16.count)) {
    //Use `Range.init(_:in:)` to convert `NSRange` to `Range<String.Index>`.
    let range = Range(match.range, in: str)!
    //When you can accept `Substring`, `String.init(_:)` is not needed.
    let matchingStr = String(str[range])
    print(matchingStr) //->:text:
} else {
    print("*NO mathes*")
}