在Swift中取消转义反斜杠

7

我希望能够将用户输入字符串中的反斜杠进行转义,以便用于正则表达式替换。

使用NSRegularExpression.escapedTemplate(for: "\\n")很容易就可以转义反斜杠。这会返回所期望的"\\\\n"。但是,我该如何进行反向转换,例如,将\\n(反斜杠+n)转换为\n(回车)呢?

5个回答

13

我不认为这可以自动完成,但是由于Swift中只有几个转义字符,您可以将它们放入数组中,循环遍历它们,然后用未转义的版本替换所有实例。这是我创建的一个String扩展程序,可以执行此操作:

extension String {
    var unescaped: String {
        let entities = ["\0", "\t", "\n", "\r", "\"", "\'", "\\"]
        var current = self
        for entity in entities {
            let descriptionCharacters = entity.debugDescription.characters.dropFirst().dropLast()
            let description = String(descriptionCharacters)
            current = current.replacingOccurrences(of: description, with: entity)
        }
        return current
    }
}

要使用它,只需访问该属性。例如,
print("Hello,\\nWorld!".unescaped) 

将打印

Hello,
World!

我刚刚发现在Swift中这种转义字符是有限制的。如果没有什么神奇、简单的方法,最好是扩展String并创建原始属性。谢谢。 - 1024jp
1
dropFirst().dropLast()方法无法使用'characters':请直接使用String @kabiroberai,此方法不起作用。 - Raja Saad

4

这里是关于字符串的转义和非转义

let given =     "{\n\t\"test\": \"this  \\ \",\n\r\t\"\'testing\': 1\r\n}\\ \0 \\"
let expected = #"{\n\t\"test\": \"this  \\ \",\n\r\t\"\'testing\': 1\r\n}\\ \0 \\"#
let expectedAscii = #"{\n\t\"test\": \"this \u{0001F603} \\ \",\n\r\t\"\'testing\': 1\r\n}\\ \0 \\"#

extension String {
    private static let escapedChars = [
        (#"\0"#, "\0"),
        (#"\t"#, "\t"),
        (#"\n"#, "\n"),
        (#"\r"#, "\r"),
        (#"\""#, "\""),
        (#"\'"#, "\'"),
        (#"\\"#, "\\")
    ]
    var escaped: String {
        self.unicodeScalars.map { $0.escaped(asASCII: false) }.joined()
    }
    var asciiEscaped: String {
        self.unicodeScalars.map { $0.escaped(asASCII: true) }.joined()
    }
    var unescaped: String {
        var result: String = self
        String.escapedChars.forEach {
            result = result.replacingOccurrences(of: $0.0, with: $0.1)
        }
        return result
    }
}

print(expected == given.escaped)
print(expectedAscii == given.asciiEscaped)
print(given.escaped.unescaped == given)
print(expected.unescaped == given)
print(expected.unescaped.escaped == expected)

1

我认为最简单的方法是使用stringByReplacingOccurrencesOfString

let input = "My name is \\n and \\n"
let firstmod = input.stringByReplacingOccurrencesOfString("\\n", withString: "\n", options: [], range: nil)

Input : "My name is \\n and \\n"
Output: "My name is \n and \n"

我想以一般的方式来做,而不是将\\转换为\,而是将\转换为\。就像\\n转换为\n\\t转换为\t - 1024jp
但是\r\"\\怎么办呢?好吧,这是一种替换所有这些组合的方法... - 1024jp
使用循环迭代并更改元素。 - Oleg Gordiichuk
很遗憾,这似乎是唯一的方法。谢谢。 - 1024jp

1
我已经改进了@kabiroberai的代码,使其更加实用,并消除了剩余的单个反斜杠。
extension String {
    var unescaped: String {
        let entities = ["\0": "\\0",
                        "\t": "\\t",
                        "\n": "\\n",
                        "\r": "\\r",
                        "\"": "\\\"",
                        "\'": "\\'",
                        ]

        return entities
            .reduce(self) { (string, entity) in
                string.replacingOccurrences(of: entity.value, with: entity.key)
            }
            .replacingOccurrences(of: "\\\\(?!\\\\)", with: "", options: .regularExpression)
            .replacingOccurrences(of: "\\\\", with: "\\")
    }
}

更新

我发现我之前的代码在某些情况下没有正确进行反转义。

所以,我更新了我的生产代码。以下是我目前使用的最新版本。 我不确定我是否真的需要这么复杂的过程,但它现在似乎工作得更好了。

var unescaped: String {
    let entities = ["\0": "0",
                    "\t": "t",
                    "\n": "n",
                    "\r": "r",
                    "\"": "\"",
                    "\'": "'",
                    ]

    return entities
        .mapValues { try! NSRegularExpression(pattern: "(?<!\\\\)(?:\\\\\\\\)*(\\\\" + $0 + ")") }
        .reduce(self) { (string, entity) in
            entity.value.matches(in: string, range: string.nsRange)
                .map { $0.range(at: 1) }
                .reversed()
                .reduce(string) { ($0 as NSString).replacingCharacters(in: $1, with: entity.key) }
        }
}

最后两行使用 .replacingOccurrences(...) 是用来干什么的?你的解决方案好像没有它们也能正常工作。 - maxkonovalov
2
Type of expression is ambiguous without more context - Vyacheslav
这个太不必要复杂了,一点意义都没有。看看下面Popmedic的解决方案。 - Mamouneyya

0

对我来说,这些答案都没有起作用,以下是让我成功的方法:

extension String {

    var unescaped: String {
        guard let convertedString = (self as NSString).mutableCopy() as? NSMutableString else {
            return self
        }
        CFStringTransform(convertedString, nil, NSString(string: "Any-Hex/Java"), true)
        return String(convertedString)
    }
}

当我尝试这个时,它只是取消转义了\u-(Unicode十六进制代码点)转义。例如,print("X\\u000AY\\nZ".unescaped) 只将第一个转义变成了换行符,但不是第二个。(如果它起作用的话,X、Y和Z都会输出为单独的行。但Y和Z在一行上,由字面上的字符\n分隔。)这实际上与“Any-Hex”转换的文档一致。它只指示Unicode代码点转义,而不是其他类型。虽然很有趣,但我以前从未听说过这个函数。 - ecp

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