如何在Swift中从字符串中去除空格?

9
我需要删除标点符号周围的前导和尾随空格。
例如: Hello , World ... I 'm a newbie iOS Developer. 我希望得到: > Hello, World... I'm a newbie iOS Developer. 我该如何做?我尝试获取字符串的组件并枚举句子,但这不是我需要的。

这种类型的函数被称为 trim()。 - zvone
1
我认为去除空格不会达到他们想要的效果。请注意,期望结果中仍然有空格。这比那要复杂得多。 - Catfish_Man
2
@zvone 不,trim只适用于字符串的开头和结尾,它不会查找字符串内部。 - Eric Aya
1
我认为你最好研究一下正则表达式(RegEx)。虽然我只是略知一二,但你可以设置一个表达式来查找标点符号旁边的空格,并将其替换为仅有的标点符号。这肯定需要进行大量的测试和实验才能得到正确的表达式。 - theMikeSwan
你可以访问regexpal.com尝试各种表达式并查看哪些有效。 - theMikeSwan
我没有电脑,无法为您提供示例。但如果它始终是自然语言字符串,特别是如果您需要支持英语以外的其他语言,则可以查看NSLinguisticTagger,它具有标点符号和空格标记。介绍:http://nshipster.com/nslinguistictagger/ 文档:https://developer.apple.com/documentation/foundation/nslinguistictagger - Dad
8个回答

8

Rob的回答很赞,但您可以利用\p{Po}正则表达式类将其大大简化。 然后,消除标点符号周围的空格就变成了一个正则表达式替换:

import Foundation

let input = "Hello ,  World ... I 'm a newbie iOS Developer."
let result = input.replacingOccurrences(of: "\\s*(\\p{Po}\\s?)\\s*",
                                        with: "$1",
                                        options: [.regularExpression])
print(result) // "Hello, World... I'm a newbie iOS Developer."

Rob的答案也试图修剪前导/尾随空格,但您的输入没有这些内容。 如果您在意这一点,只需对结果调用result.trimmingCharacters(in:.whitespacesAndNewlines)


以下是正则表达式的解释。 去除双转义符后,它看起来像

\s*(\p{Po}\s?)\s*

这由以下组件组成:

  • \s* - 匹配零个或多个空白字符(并将其丢弃)
  • (…) - 捕获组。括号内的所有内容都会被保留并在替换中使用(替换中的$1指的是该组)。
    • \p{Po} - 匹配一个位于“Other_Punctuation”Unicode类别中的单个字符。这包括像.'之类的字符,但不包括像(-之类的字符。
    • \s? - 匹配一个可选的空格字符。这将保留句号(或省略号)后面的空格。
  • \s* - 再次匹配零个或多个空白字符(并将其丢弃)。这就是将, World转换为, World的方法。

1
你可以直接在字符串上使用 .replacingOccurrences(of: "\\s*(\\p{Po}\\s?)\\s*", with: "$1", options: .regularExpression) - Leo Dabus
1
@LeoDabus 好主意,我已经更新了我的答案来使用它。 - Lily Ballard
你能帮我看一下这个正则表达式吗?https://stackoverflow.com/a/46551178/2303865 我认为它是正确的。 - Leo Dabus

7
对于Swift 3或4,您可以使用:
let trimmedString = string.trimmingCharacters(in: .whitespaces)

8
只有当你的空格在字符串的开头或结尾时,这种方法才有效。它会忽略单词间的任何空格。 - Makoren

5
这是一个非常棒的问题,可惜现在在Swift中做起来不太容易(总有一天会变得容易,但今天不行)。
我有点讨厌这段代码,但我将要坐20个小时的飞机,没有时间让它更加美观。这至少可以让你开始使用NSMutableString。能够使用String就更好了,但是Swift不喜欢正则表达式,所以这有点丑陋,但至少是一个开始。
import Foundation

let input = "Hello,  World ... I 'm a newbie iOS Developer."

let adjustments = [
    (pattern: "\\s*(\\.\\.\\.|\\.|,)\\s*", replacement: "$1 "), // elipsis or period or comma has trailing space
    (pattern: "\\s*'\\s*", replacement: "'"), // apostrophe has no extra space
    (pattern: "^\\s+|\\s+$", replacement: ""), // remove leading or trailing space
]

let mutableString = NSMutableString(string: input)

for (pattern, replacement) in adjustments {
    let re = try! NSRegularExpression(pattern: pattern)
    re.replaceMatches(in: mutableString,
                      options: [],
                      range: NSRange(location: 0, length: mutableString.length),
                      withTemplate: replacement)
}
mutableString // "Hello, World... I'm a newbie iOS Developer."

当你第一次遇到正则表达式时,可能会感到非常困惑。以下是一些阅读提示:

  • Foundation使用的具体语言由ICU描述。

  • 反斜杠(\)在正则表达式中表示“下一个字符是特殊字符”。但在Swift字符串内部,反斜杠表示字符串的下一个字符是特殊字符。因此,您需要将它们全部加倍。

  • \s 表示“空格字符”

  • \s* 表示“零个或多个空格字符”

  • \s+ 表示“一个或多个空格字符”

  • $1 表示“我们在括号中匹配的内容”

  • | 表示“或”

  • ^ 表示“字符串的开头”

  • $ 表示“字符串的结尾”

  • . 表示“任何字符”,所以要表示“实际点号”,您需要在Swift字符串中输入“\\.”。

请注意,我在同一个正则表达式中检查了“...”和“.”。你必须这样做,否则“.”在“...”内部会匹配三次。另一种方法是先用“…”(Mac上按Opt-;键输入的单个省略号字符)替换“...”。然后,“…”就是一个单字符的标点符号。(您也可以决定在处理结束时重新将所有省略号展开为点点点。)
在真实生活中,我可能会像这样完成和交付工作,但尝试逐个字符地构建此字符状态机并跟踪当前状态可能值得一试。

在你的正则表达式中,你可以使用\p{Po}来涵盖“其他标点符号”类别,其中包括.'。这样你就不需要硬编码标点符号了。 - Lily Ballard
@KevinBallard 这里行不通,因为 .' 有不同的规则。 . 需要一个尾随空格,但是 '(至少这种使用方式)需要没有尾随空格。随着该算法逐渐增长以处理许多边角情况,“其他标点符号”将变得更加僵硬。我相信您会发现需要硬编码更多的标点符号来处理这些复杂性。 - Rob Napier
在样本输入中,没有带有尾随空格的 ' 实例。我不清楚是否需要处理它。 - Lily Ballard

2
您可以尝试类似于string.replacingOccurrences(of: " ,", with: ",")这样的方法来处理每个标点符号...

1

程序相关内容:如何从字符串中删除空格,下面是我知道的最简单的方法:

originalString.filter { $0 != " " }

由于字符串本身就是一个数组,我们可以对其使用所有的数组函数。


但是楼主并不想删除所有空格。 - HangarRash

0
有趣的问题;这里是我尝试非正则表达式方法的结果:
func correct(input: String) -> String {
    typealias Correction = (punctuation: String, replacement: String)

    let corrections: [Correction] = [
        (punctuation: "...", replacement: "... "),
        (punctuation: "'", replacement: "'"),
        (punctuation: ",", replacement: ", "),
    ]

    var transformed = input
    for correction in corrections {
        transformed = transformed
            .components(separatedBy: correction.punctuation)
            .map({ $0.trimmingCharacters(in: .whitespaces) })
            .joined(separator: correction.replacement)
    }

    return transformed
}

let testInput = "Hello , World ... I 'm a newbie iOS Developer."
let testOutput = correct(input: testInput)

// Hello, World... I'm a newbie iOS Developer.

0

如果您手动处理字符数组,只需检查空格周围的前一个和后一个字符即可。使用zip、filter和map等函数式编程,您可以实现相同的结果:

let testInput = "Hello , World ... I 'm a newbie iOS Developer."

let punctuation    = Set(".\',")
let previousNext   = zip( [" "] + testInput, String(testInput.dropFirst()) + [" "] )
let filteredChars  = zip(Array(previousNext),testInput)
                    .filter{  $1 != " "
                              || !($0.0 != " " && punctuation.contains($0.1))
                           }
let filteredInput = String(filteredChars.map{$1})

print(testInput)     // Hello , World ... I 'm a newbie iOS Developer.
print(filteredInput) // Hello, World... I'm a newbie iOS Developer.

-4

Swift 4、4.2和5

let str = "  Akbar Code  "
let trimmedString = str.trimmingCharacters(in: .whitespaces)

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