2017-10-17 10 views
0

CharacterクラスがtoUpper()toLower()をサポートしない理由を理解していますが、私の使用例は言語目的ではありません。さらに、NSStringに戻すことは望ましくありません。Swift 4で文字を大文字または小文字に変換する最速の方法は?

Swift 4を使用して文字を大文字または小文字に変換する最も速い方法は何ですか?

// Is there something better than this? 
extension Character { 
    func toLower() -> Character { 
     return String(self).lowercased().first! 
    } 
} 

答えて

3

あなただけの最初の文字を大文字する必要がある場合は、以下のuppercase2()を使用してください。それは文字列全体を大文字にするよりも5倍のスピードアップです。千万目で

import Foundation 

// too slow, maybe with some bitwise operations could get faster ‍♀️ 
func uppercase(_ string: String) -> Character? { 
    let key: Int8 = string.utf8CString[0] 
    guard key>0, key<127, let c = Unicode.Scalar(Int(key >= 97 ? key - Int8(32) : key)) else { return nil } 
    return Character(c) 
} 

// winner but using internal _core stuff 
func uppercase2(_ string: String) -> Character? { 
    guard let key = string._core.asciiBuffer?[0] else { return nil } 
    return Character(Unicode.Scalar(key >= 97 ? key - 32 : key)) // use < + to lowercase 
} 

func measure(times: Int, task:()->()){ 
    let start1 = CFAbsoluteTimeGetCurrent() 
    for _ in 1..<times { 
     task() 
    } 
    print(CFAbsoluteTimeGetCurrent() - start1) 
} 

print("".uppercased().first as Any) // Optional("") 
print(uppercase("") as Any) // nil 
print(uppercase2("") as Any) // nil 

measure(times: 10_000_000) { _ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".uppercased().first } // 4.17883902788162 
measure(times: 10_000_000) { _ = uppercase("ABCDEFGHIJKLMNOPQRSTUVWXYZ") }   // 4.91275697946548 
measure(times: 10_000_000) { _ = uppercase2("ABCDEFGHIJKLMNOPQRSTUVWXYZ") }  // 0.720575034618378 

、Appleのuppercasedでも力アンラップで、より速くこの記事の下部にあるコードよりも148x回走りました。私はコメディー目的のためにそれを残すでしょう。

彼らのアプローチはもちろん、低レベルです。 lowercased()を参照してください。彼らは、内部asciiBufferを確認し、_asciiUpperCaseTableを使用します。

元のStringがすでにSwift Stringの場合は、ASCIIレベルの文字を扱うように既に最適化されたStringCoreクラスで表されます。したがって、Swiftの大文字の機能を破ることはできません。

答えの種類:最も速い方法は、通常のuppercase()関数を使用することです。


「私のユースケースは言語目的ではない」とは、私がASCIIのみを使用していることを意味します。これが提供する利点は、UTF-8とASCIIが同じスカラーコードを共有しているため、上/下ケーシングは固定数を減算または追加することを意味します。

import Foundation 

print("a".unicodeScalars.first!.value) // 97 
print("A".unicodeScalars.first!.value) // 65 

let uppercase = String("abcde".flatMap { 
    guard let char = $0.unicodeScalars.first, 
      let uppercased = Unicode.Scalar(char.value - UInt32(97 - 65)) 
    else { 
     return nil 
    } 
    return Character(uppercased) 
}) 

print(uppercase) // ABCDE 
+0

おかげさまで、詳細な答えをいただきありがとうございました。第2に、私はStringクラスのソースコードを見ることができます。私の場合、私はASCII文字列の最初の文字を取得しており、それを下位または大文字のいずれかに強制して辞書のキーとして使用します。私は文字列全体に対してlowercased()を実行し、最初の文字を取得できますが、コードのサブセットを使用する方が良いでしょうか? –

+0

文字列全体を大文字にするよりも6倍速の場合は、大文字2を参照してください。それでも、コードを改善する方法はたくさんありますが、現時点でどうなっているのか分かりません。 – Jano

関連する問題