如何使用Swift识别字符串中的大写和小写字符?

40
这是我目前为止的进展(仅用于测试):
let string = "The quick BroWn fOX jumpS Over tHe lazY DOg"

for chr in string {
    if isupper(String(chr)) {
        print(String(chr).lowercaseString)
        continue
    }
    print(chr)
}

如何测试大写和小写字符?

我知道可以从Swift调用C函数,但这对我并不正确。如何仅使用Swift完成此操作?


你想对结果做什么?获取一个包含所有大写字符的字符串吗? - Joachim Isaksson
不。我想知道如何测试大写和小写字符。我提供了一个例子以便完整。 - yeyo
2
这里有什么问题?是 isupper 函数调用吗?如果你只是想知道字符串中是否有大写字符,也许可以用 if string.lowercaseString == string - Jack
18个回答

22

我不确定您所说的“避免C函数”的意思。我希望这不包括在开发应用程序时使用OS X和iOS提供的框架和基础库,例如NSCharacterSet类,它提供了与Unicode兼容的实现所需的准确功能。

为了进一步回答Matt的答案,并使其更符合您问题的要求:

import UIKit

let testString = "Åke röstet un café in Владивосток!"
let lowerCase = NSCharacterSet.lowercaseLetterCharacterSet()
let upperCase = NSCharacterSet.uppercaseLetterCharacterSet()

for currentCharacter in testString.utf16 {
  if lowerCase.characterIsMember(currentCharacter) {
    println("Character code \(currentCharacter) is lowercase.")
  } else if upperCase.characterIsMember(currentCharacter) {
    println("Character code \(currentCharacter) is UPPERCASE.")
  } else {
    println("Character code \(currentCharacter) is neither upper- nor lowercase.")
  }
}

Swift 3

let testString = "Åke röstet un café in Владивосток!"
let lowerCase = CharacterSet.lowercaseLetters
let upperCase = CharacterSet.uppercaseLetters

for currentCharacter in testString.unicodeScalars {
    if lowerCase.contains(currentCharacter) {
        print("Character code \(currentCharacter) is lowercase.")
    } else if upperCase.contains(currentCharacter) {
        print("Character code \(currentCharacter) is UPPERCASE.")
    } else {
        print("Character code \(currentCharacter) is neither upper- nor lowercase.")
    }
}

@DavidH 我不太确定,似乎有点低效,总体来说它似乎是一个O(NM)的操作(对于每个元素执行一次搜索)。而被接受的答案似乎是(不完全确定)一个O(n log n)的操作。这里需要注意的重要事项是,解决方案的性能取决于 CharacterSet.lowercaseLetters 的大小。 - yeyo
@yeyo 所选答案并不真正回答了问题——如何找到三种类型的字符:小写、大写和没有大小写的字符。请注意,“包含”操作使用哈希(类似于集合、字典),因此相对较快。我怀疑这比创建一个字符串要快得多,就像在选定的答案中所做的那样,但你需要自己进行基准测试。 - David H
确实,需要进行基准测试。使用Xcode,我可以确认CharacterSet.lowercaseLetters不是一个数组,而且说实话,名称本身就表明它是一个SET,这改变了我对它的看法。通过else子句,接受的答案确实转换了大写和小写字符,这实际上也是我的问题(最初),但是这个答案似乎是解决问题的更好方法,我会测试并更改接受的答案。谢谢。 - yeyo

20

你可以始终查看小写表示形式是否与当前值不同;

let string = "The quick BroWn fOX jumpS Over tHe lazY DOg"
var output = ""

for chr in string {
    var str = String(chr)
    if str.lowercaseString != str {
        output += str
    }
}
print(output)

>>> TBWOXSOHYDO

6
这真是太疯狂了,所有正常的语言都有检查字符是否为大写字母或小写字母的功能。那数字和其他种类的字符呢?(抱歉,我在发牢骚) - Andrey
确实,我查了一下,似乎在Swift中没有找到这样的功能。:\ 也许我没有找够。 - yeyo
1
我认为lowercaseString和uppercaseString这两个方法已经从Swift中删除了。 - Nitesh
1
@Andrey Swift正在实现一种现代的String类型,使本地化比以前更容易,并且同时将其整合到具有所有历史包袱的现有Objective-C环境中。如果你想成为一个来自70年代的英语中心主义者,完全可以使用类似以下代码的东西: for cu in s.utf8 { if isdigit(Int32(cu)) == 1 { println("\(cu) is a digit") } }除非你生活在ASCII世界中,否则我建议在更改或测试文本大小写时使用.lowercaseString()或更好的.lowercaseStringWithLocale()方法。 - guidos
是的,这些模式非常疯狂,非常慢,因为它们是O(N^2)或更糟糕,因为存在不必要的对象(con/de)struction。因为这个垃圾,我的应用现在需要超过1分钟才能解析和清理少于1k个名称、地址和电话号码。 - user246672
显示剩余5条评论

20
在Swift 5中,我们现在可以按照Unicode标准检查字符属性
对于您的问题,chr.isUppercasechr.isLowercase是答案。

10

通过扩展StringCharacter,我认为我已经得到了一个相当灵活的解决方案,它完全(?)支持Unicode。 下面的语法适用于Swift 3.0。虽然在Swift 2.x中也应该是可行的。

extension String {
    func isUppercased(at: Index) -> Bool {
        let range = at..<self.index(after: at)
        return self.rangeOfCharacter(from: .uppercaseLetters, options: [], range: range) != nil
    }
}

extension Character {
    var isUppercase: Bool {
      let str = String(self)
      return str.isUppercased(at: str.startIndex)
    }
}

let str = "AaÀàΓγ!2"
let uppercase = str.characters.filter({ $0.isUppercase }) // ["A", "À", "Γ"]
for char in str.characters {
    "\(char): \(char.isUppercase)"
}

// A: true
// a: false
// À: true
// à: false
// Γ: true
// γ: false
// !: false
// 2: false
// : false
// : false

这些扩展的TODO是将Character上的isUppercase重构,以免转换为String


7
在Swift 3中,我会做这样的事情
import UIKit
...
let ch = "A".unicodeScalars.first!
let is_ch_upperCase = CharacterSet.uppercaseLetters.contains(ch)

6

SWIFT 4:

除非您正在检查数字或Unicode标量等内容,否则您只需简单地执行此操作即可,无需进行其他繁琐的操作。

extension String {

   var isLowercase: Bool {
       return self == self.lowercased()
   }

   var isUppercase: Bool {
       return self == self.uppercased()
   }

}

5

清洁,但可能比循环慢:

let str = "The quick BroWn fOX jumpS Over tHe lazY DOg"
let nonUpperCase = NSCharacterSet.uppercaseLetterCharacterSet().invertedSet
let letters = str.componentsSeparatedByCharactersInSet(nonUpperCase)
"".join(letters) // "TBWOXSOHYDO"

4

在Bob Prystanek的函数基础上,您可以扩展Swift的“Character”类。只需将以下扩展放在代码中的任何位置,现在您可以询问任何字符是否为大写。

extension Character
{
    public func isUpper() -> Bool
    {
        let characterString = String(self)
        return (characterString == characterString.uppercaseString) && (characterString != characterString.lowercaseString)
    }
}

3

这个简单的扩展可以接受任何CharacterSet进行检查:

extension String {
    func hasCharacter(in characterSet: CharacterSet) -> Bool {
        return rangeOfCharacter(from: characterSet) != nil
    }
}

使用方法:

"aBc".hasCharacter(in: .lowercaseLetters)
"aBc".hasCharacter(in: .uppercaseLetters)
"aBc".hasCharacter(in: <#AnyOtherCharacterSetYouWant#>)

2

添加这个Swift扩展,以便所有的Character类实例都有两个新的函数:isUpperCase()用于测试字符是否为大写,isLowerCase()用于测试字符是否为小写。实现只需检查字符实例是否在所需的集合中。

extension Character {

        func isUpperCase() -> Bool {
            return CharacterSet.uppercaseLetters.contains(self.unicodeScalars.first!)
        }

        func isLowerCase() -> Bool {
            return CharacterSet.lowercaseLetters.contains(self.unicodeScalars.first!)
        }

  }

你的回答只包含代码。如果您能添加一些评论来解释它的作用和方式,那将更好。您可以编辑您的回答并添加吗?谢谢! - Fabio says Reinstate Monica

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