Swift 中的正则表达式

5

我对 Swift 中的 NSRegularExpression 有些困惑,能有人帮我吗?

任务1:给定 ("name", "john", "name of john")
我应该得到 ["name", "john", "name of john"]。在这里,我应该避免括号。

任务2:给定 ("name", " john", "name of john")
我应该得到 ["name", "john", "name of john"]。在这里,我应该避免括号和额外的空格,并最终获取字符串数组。

任务3:给定 key = value // comment
我应该得到 ["key", "value", "comment"]。在这里,我应该通过避免使用等号和“//”来仅获取行中的字符串。
我已经尝试了以下代码来完成任务1但未成功。

let string = "(name,john,string for user name)"
let pattern = "(?:\\w.*)"

do {
    let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    let matches = regex.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
    for match in matches {
        if let range = Range(match.range, in: string) {
            let name = string[range]
            print(name)
        }
    }
} catch {
    print("Regex was bad!")
}


提前感谢。


1
你发布的代码中的 string 值与你问题中提供的任何“给定”任务都不匹配。一个有引号,另一个没有。 - rmaddy
请注意,任务3应该是与前两个任务分开的单独问题。 - rmaddy
这只是用户输入,可能会给出,也可能不会。例如,不带引号。感谢@rmaddy的回复。 - Damodar
您的任务1使用了("name","john","name of john"),但是您的代码片段使用了(name,john,string for user name),那么到底是哪种方式呢?是在子字符串周围加上引号还是不加? - Rob
此外,你举了一些例子,其中你的子字符串本身不包括引号或逗号。但如果他们确实包括(例如,在子字符串中有某些转义字符),该怎么办呢?如果需要处理这种情况,你开始进入一个正则表达式可能根本不是最佳选择的领域。 - Rob
5个回答

3

Swift中的正则表达式

以下文章可以帮助您探索Swift中的正则表达式:

任务1和2

这个表达式可能帮助您匹配任务1和任务2的期望输出:
"(\s+)?([a-z\s]+?)(\s+)?"

enter image description here


根据Rob的建议,您可以大大减少边界,例如字符列表[a-z\s]。例如,在这里,我们也可以使用:

"(\s+)?(.*?)(\s+)?"

或者

"(\s+)?(.+?)(\s+)?"

简单地传递两个 " 和/或 空格 之间的所有内容。

enter image description here

正则表达式

如果这不是你想要的表达式,你可以在regex101.com上进行修改/更改。

正则表达式电路

你也可以在jex.im中可视化你的表达式:

enter image description here

JavaScript演示

const regex = /"(\s+)?([a-z\s]+?)(\s+)?"/gm;
const str = `"name","john","name of john"
"name","       john","name of john"
"       name  ","       john","name of john     "
"       name  ","       john","       name of john     "`;
const subst = `\n$2`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

任务三

这个表达式 可能会帮助你设计第三个任务的表达式:

(.*?)([a-z\s]+)(.*?)

enter image description here

const regex = /(.*?)([a-z\s]+)(.*?)/gm;
const str = `key = value // comment
key = value with some text // comment`;
const subst = `$2,`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);


3
并非我的投票,但请注意答案需要使用Swift而不是JavaScript。 - rmaddy
1
我不会使用 a-z。这样无法接受带有重音的字符串。例如,如果名称是“José”。我只会搜索 [^"]+。此外,无需捕获目标字符串前后的空格。 - Rob

2
将字符串按非字母数字字符(除了空格)分隔。然后修剪带有空格的元素。最初的回答:

通过非字母数字字符(不包括空格)分隔字符串,然后去除带有空格的元素。

extension String {
    func words() -> [String] {
        return self.components(separatedBy: CharacterSet.alphanumerics.inverted.subtracting(.whitespaces))
                .filter({ !$0.isEmpty })
                .map({ $0.trimmingCharacters(in: .whitespaces) })
    }
}

let string1 = "(name,john,string for user name)"
let string2 = "(name,       john,name of john)"
let string3 = "key = value // comment"

print(string1.words())//["name", "john", "string for user name"]
print(string2.words())//["name", "john", "name of john"]
print(string3.words())//["key", "value", "comment"]

谢谢@Rajeshkumar。你能帮我理解Rex吗?当我在测试VSCode时,它可以工作,但在Swift中却不行。 - Damodar
3
请记住,对于字符串3中许多可能的值,此解决方案将失败。并且对于任何包含连字符、撇号或其他标点符号的名称,它都可能会失败。 - rmaddy

1

在理解了以上所有评论后,我已经完成了这个任务。

let text = """
Capturing and non-capturing groups are somewhat advanced topics. You’ll encounter examples of capturing and non-capturing groups later on in the tutorial
"""

extension String {
            func  rex (_ expr : String)->[String] {
                return try! NSRegularExpression(pattern: expr, options: [.caseInsensitive])
                .matches(in: self, options: [], range: NSRange(location: 0, length: self.count))
                    .map {
                        String(self[Range($0.range, in: self)!])
                }
            }
        }
let r = text.rex("(?:\\w+-\\w+)") // pass any rex

0
一个适用于 Swift 中测试 1...3 的单一模式。
let string =
    //"(name,john,string for user name)" //test:1
    //#"("name","       john","name of john")"# //test:2
    "key = value // comment" //test:3

let pattern = #"(?:\w+)(?:\s+\w+)*"# //Swift 5+ only
//let pattern = "(?:\\w+)(?:\\s+\\w+)*"

do {
    let regex = try NSRegularExpression(pattern: pattern)
    let matches = regex.matches(in: string, range: NSRange(0..<string.utf16.count))
    let matchingWords = matches.map {
        String(string[Range($0.range, in: string)!])
    }
    print(matchingWords) //(test:3)->["key", "value", "comment"]
} catch {
    print("Regex was bad!")
}

0

让我们考虑一下:

let string = "(name,José,name is José)"

我建议使用正则表达式来查找以下字符串:

  • 它是完整字符串开头的(或逗号后面的子字符串,即使用(?<=^\(|,)进行断言;
  • 它是不包含,的子字符串,即使用[^,]+?
  • 它是以逗号或)结尾的子字符串,即使用(?=,|\)$)进行断言;
  • 如果你想要在子字符串前后跳过空格,也可以加上\s*+

因此:

let pattern = #"(?<=^\(|,)\s*+([^,]+?)\s*+(?=,|\)$)"#
let regex = try! NSRegularExpression(pattern: pattern)
regex.enumerateMatches(in: string, range: NSRange(string.startIndex..., in: string)) { match, _, _ in
    if let nsRange = match?.range(at: 1), let range = Range(nsRange, in: string) {
        let substring = String(string[range])
        // do something with `substring` here
    }
}

请注意,我正在使用Swift 5扩展字符串定界符(以#"开头,以"#结尾),这样我就不必在字符串内转义反斜杠。如果您使用的是Swift 4或更早版本,则需要转义这些反斜杠:

let pattern = "(?<=^\\(|,)\\s*+([^,]+?)\\s*+(?=,|\\)$)"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接