【问题标题】:How to Check if String begins with Alphabet Letter in Swift 5?如何在 Swift 5 中检查字符串是否以字母开头?
【发布时间】:2020-12-18 16:27:06
【问题描述】:

问题:我目前正在根据Items First Character尝试Sort a List in SwiftUI。我还想为所有项目实现Section,其中doesn't beginCharacter of the Alphabet (数字,特殊字符)

到目前为止我的代码:

let nonAlphabetItems = items.filter { $0.name.uppercased() != /* beginns with A - Z */ }

有没有人有这个问题的解决方案。当然我可以做一个巨大的循环构造,但是我希望有一个更优雅的方式。

感谢您的帮助。

【问题讨论】:

  • 字母包括非标准字母还是只有“A”...“Z”? “Ç”应该被认为是一个字母吗?
  • @LeoDabus 只有标准字母“A”到“Z”。像“Ç”这样的特殊字母以及数字和特殊字符应该通过过滤。
  • @LeoDabus "Ç" 是一个标准字母:它是 Unicode 标准,该标准将其识别为字母。希腊字母或西里尔字母也有很多标准字母。我想“非标准”是指“non roman”? ;-)
  • @Christophe 这就是我问的原因。 Ç 是一个字母,但它不在英文字母表中
  • @LeoDabus 抱歉,无意冒犯。我什至赞成你有趣的答案。我用术语取笑你。 “标准字母”不是“英文字母”,除了 79 亿 people in the world 中的 3.79 亿 English-native speakers。所以世界上 96% 的人对“标准字母”有另一种理解 ;-) 顺便说一下,英文字母甚至不是英文,它是罗马/拉丁 ;-)

标签: ios swift string alphabetical


【解决方案1】:

您可以检查字符串范围 "A"..."Z" 是否包含您的 name 属性的第一个字母:

struct Item {
    let name: String
}

let items: [Item] = [.init(name: "Def"),.init(name: "Ghi"),.init(name: "123"),.init(name: "Abc")]

let nonAlphabetItems = items.filter { !("A"..."Z" ~= ($0.name.first?.uppercased() ?? "#")) }

nonAlphabetItems  // [{name "123"}]

扩展这个主题,我们可以扩展 Character 以添加 isAsciiLetter 属性:

extension Character {
    var isAsciiLetter: Bool { "A"..."Z" ~= self || "a"..."z" ~= self }
}

这将允许扩展 StringProtocol 以检查是否以 ascii 字母开头的字符串:

extension StringProtocol {
    var startsWithAsciiLetter: Bool { first?.isAsciiLetter == true }
}

而且只是一个否定布尔属性的助手:

extension Bool {
    var negated: Bool { !self }
}

现在我们可以按如下方式过滤项目集合:

let nonAlphabetItems = items.filter(\.name.startsWithAsciiLetter.negated)   // [{name "123"}]

【讨论】:

  • 感谢您的回答。 ~= 运算符到底是什么?
  • 在这种情况下它与包含相同。它被称为模式匹配运算符。这也可以写成{!("A"..."Z").contains(($0.name.first?.uppercased() ?? "#")) }
【解决方案2】:

如果您需要一个偶尔的过滤器,您可以简单地编写一个组合标准谓词isLetterisASCII 的条件,这些谓词已经为Character 定义。很简单:

let items = [ "Abc", "01bc", "Ça va", "", "  ", "????"]
let nonAlphabetItems = items.filter { $0.isEmpty || !$0.first!.isASCII || !$0.first!.isLetter }
print (nonAlphabetItems)  // -> Output:  ["01bc", "Ça va", "", "  ", "????"]

如果字符串不为空,它肯定有第一个字符$0.first!。使用 isLetter 很诱人,但对于许多本地字母表中的许多字符来说似乎都是正确的,例如像 "?" 这样的古董 Egyptian hieroglyphs 或带有 "Ç" 和重音字符的法语字母表。这就是为什么您需要将其限制为 ASCII 字母,以限制自己使用 roman alphabet

【讨论】:

  • 无需强制解包$0.isEmpty || $0.first?.isASCII == false || $0.first?.isLetter == false
【解决方案3】:

您可以通过以下方式使用 NSCharacterSet:


let phrase = "Test case"
let range = phrase.rangeOfCharacter(from: characterSet)

// range will be nil if no letters is found
if let test = range {
    println("letters found")
}
else {
   println("letters not found")
}```

【讨论】:

  • OP 正在尝试仅检查第一个字符“开始于”
【解决方案4】:

你可以处理ascii值

extension String {
    var fisrtCharacterIsAlphabet: Bool {
         guard let firstChar = self.first else { return false }
         let unicode = String(firstChar).unicodeScalars
         let ascii = Int(unicode[unicode.startIndex].value)
         return (ascii >= 65 && ascii <= 90) || (ascii >= 97 && ascii <= 122)
    }
    
}

var isAlphabet = "Hello".fisrtCharacterIsAlphabet

【讨论】:

    【解决方案5】:

    Character 类型有一个属性:

    let x: Character = "x"
    x.isLetter // true for letters, false for punctuation, numbers, whitespace, ...
    

    请注意,这将包括来自其他字母(希腊语、西里尔文、中文...)的字符。

    由于StringSequenceElement 等于Character,我们可以使用.first 属性来获取第一个字符。

    有了这个,你可以过滤你的项目:

    let filtered = items.filter { $0.name.first?.isLetter ?? false }
    

    【讨论】:

    【解决方案6】:

    您可以通过这个简单的String 扩展来完成这项工作

    extension StringProtocol {
        var isFirstCharacterAlp: Bool {
            first?.isASCII == true && first?.isLetter == true
        }
    }
    

    用法:

    print ("H1".isFirstCharacterAlp)
    print ("ابراهيم1".isFirstCharacterAlp)
    

    输出

    true
    false
    

    编码愉快!

    Reference

    【讨论】:

    • 为什么不按照Palle 的建议简单地使用 Character 属性 isLetter?顺便说一句,这不会解决问题,因为它也将包含非 ascii 字母
    • @LeoDabus 我已经更新了我的答案。感谢您指出我忽略了 cmets 的 ASCII 约束
    • IMO self.first?.isASCII == true 读起来比 self.first?.isASCII ?? false 好得多。顺便说一句,不需要括号first?.isASCII == true &amp;&amp; first?.isLetter == true
    • 我只删除self 前缀并扩展StringProtocol 以支持子字符串
    • 同意 感谢您的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-01
    • 2016-01-05
    • 2019-08-24
    • 2015-04-15
    • 2012-02-06
    相关资源
    最近更新 更多