从字符串中获取数字字符

Mak*_*lle 4 swift swift3

如何从字符串中获取数字字符?我不想转换Int.

var string = "string_1"
var string2 = "string_20_certified"
Run Code Online (Sandbox Code Playgroud)

我的结果必须格式如下:

newString = "1"
newString2 = "20"
Run Code Online (Sandbox Code Playgroud)

dfr*_*fri 11

模式匹配的String西方阿拉伯数字的unicode标量

您可以将a 的unicodeScalars视图模式匹配String到给定UnicodeScalar模式(例如,涵盖西方阿拉伯数字).

extension String {
    var westernArabicNumeralsOnly: String {
        let pattern = UnicodeScalar("0")..."9"
        return String(unicodeScalars
            .flatMap { pattern ~= $0 ? Character($0) : nil })
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

let str1 = "string_1"
let str2 = "string_20_certified"
let str3 = "a_1_b_2_3_c34"

let newStr1 = str1.westernArabicNumeralsOnly
let newStr2 = str2.westernArabicNumeralsOnly
let newStr3 = str3.westernArabicNumeralsOnly

print(newStr1) // 1
print(newStr2) // 20
print(newStr3) // 12334
Run Code Online (Sandbox Code Playgroud)

扩展到匹配几种给定模式中的任何一种

上面的unicode标量模式匹配方法特别有用,可以将其扩展到匹配几个给定模式中的任何一个,例如描述东方阿拉伯数字的不同变化的模式:

extension String {   
    var easternArabicNumeralsOnly: String {
        let patterns = [UnicodeScalar("\u{0660}")..."\u{0669}", // Eastern Arabic
                                       "\u{06F0}"..."\u{06F9}"] // Perso-Arabic variant 
        return String(unicodeScalars
            .flatMap { uc in patterns.contains{ $0 ~= uc } ? Character(uc) : nil })
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以在实践中使用,例如,如果编写表情符号过滤器,因为覆盖表情符号的unicode标量的范围可以容易地添加到patterns上面的东部阿拉伯语示例中的阵列中.


为什么使用UnicodeScalar模式方法而不是模式Character

CharacterSwift中的A 包含扩展的字形集群,该集群由一个或多个 Unicode标量值组成.这意味着CharacterSwift中的实例在内存中没有固定大小,这意味着对O(1)中的顺序(/连续)存储字符集合中的字符的随机访问将不可用,而是O(n) ).

另一方面,Swift中的Unicode标量存储在固定大小的UTF-32代码单元中,这应该允许O(1)随机访问.现在,我不能完全肯定,如果这是事实,还是为了什么如下的理由:但事实是,如果采用基准上述方法VS等效方法CharacterView(.characters财产)的一些测试String情况下,它非常的明显UnicodeScalar方法比Character方法快; 天真的测试表明,执行时间差异为10-25倍,随着String规模的增长而稳步增长.

了解使用Unicode标量与使用Swift中的字符的限制

然而,现在,使用该UnicodeScalar方法存在缺点; 即当处理不能由单个unicode标量表示的字符时,但是其中一个unicode标量包含在我们想要匹配的模式中.

例如,考虑一个包含四个字符 的字符串"Café".最后一个字符"é"由两个unicode标量表示,"e"并且"\u{301}".如果我们要实现模式匹配,比如说,UnicodeScalar("a")...e上面应用的过滤方法将允许两个unicode标量之一通过.

extension String {
    var onlyLowercaseLettersAthroughE: String {
        let patterns = [UnicodeScalar("1")..."e"]
        return String(unicodeScalars
            .flatMap { uc in patterns.contains{ $0 ~= uc } ? Character(uc) : nil })
    }
}

let str = "Cafe\u{301}"
print(str)                               // Café
print(str.onlyLowercaseLettersAthroughE) // Cae
                                         /* possibly we'd want "Ca" or "Caé"
                                            as result here                   */
Run Code Online (Sandbox Code Playgroud)

在本问答中OP查询的特定用例中,上述问题不是问题,但根据用例,有时更适合使用Character模式匹配UnicodeScalar.


vac*_*ama 6

编辑:更新为Swift 4和5

这是一个不需要Foundation的简单方法:

let newstring = string.filter { "0"..."9" ~= $0 }
Run Code Online (Sandbox Code Playgroud)

或借用@dfri的想法进行String扩展:

extension String {
    var numbers: String {
        return filter { "0"..."9" ~= $0 }
    }
}

print("3 little pigs".numbers) // "3"
print("1, 2, and 3".numbers)   // "123"
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的注意@ uplearnedu.com。实际上,它现在更简单了,因为不需要`String()`,并且像以前一样我放弃了`self.`。查看更新。 (2认同)