【问题标题】:Swift: generate an array of (Swift) charactersSwift:生成(Swift)字符数组
【发布时间】:2014-10-01 23:47:27
【问题描述】:

简单的问题 - 希望我正在尝试生成一个简单的字符数组,类似于:

// trying to do something like this (pseudo code):
let letters:[Character] = map(0..<26) { i in 'a' + i }

尝试了以下方法无济于事

let a = Character("a")
let z = Character("z")
let r:Range<Character> = a..<z
let letters:[Character] = map(a..<z) { i in i }

我意识到 Swift 使用 Unicode,这样做的正确方法是什么?

(注意,这不是关于与旧版 Obj-C char 互操作的问题,严格在 Swift 中进行测试等)。

【问题讨论】:

    标签: ios xcode string macos swift


    【解决方案1】:

    在 Swift 中获取初始字符代码(即 c / Obj-C 中的 'a')有点麻烦,但你可以这样做:

    let aScalars = "a".unicodeScalars
    let aCode = aScalars[aScalars.startIndex].value
    
    let letters: [Character] = (0..<26).map {
        i in Character(UnicodeScalar(aCode + i))
    }
    

    【讨论】:

    • 谢谢,正在尝试在文档中找到该映射;不能。 PS。想尝试切线相关的奖金问题吗? stackoverflow.com/questions/26152604/… ;-)
    • 是的,没有很好的记录;你基本上必须挖掘自动生成的头文件,看看你能做什么;)
    【解决方案2】:

    感谢您提供有用的答案。

    我使用的是单行版本。

    let xs = (97...122).map({Character(UnicodeScalar($0))})
    

    或

    let xs = (0..<26).map({Character(UnicodeScalar("a".unicodeScalars.first!.value + $0))})
    

    【讨论】:

    • 我喜欢单线;但是我发现我需要解开 UnicodeScalar() 的输出,如下所示: let xs = (0..
    【解决方案3】:

    Xcode 12.5 • Swift 5.4

    extension ClosedRange where Bound == Unicode.Scalar {
        static let asciiPrintable: ClosedRange = " "..."~"
        var range: ClosedRange<UInt32>  { lowerBound.value...upperBound.value }
        var scalars: [Unicode.Scalar]   { range.compactMap(Unicode.Scalar.init) }
        var characters: [Character]     { scalars.map(Character.init) }
        var string: String              { String(scalars) }
    }
    

    extension String {
        init<S: Sequence>(_ sequence: S) where S.Element == Unicode.Scalar {
            self.init(UnicodeScalarView(sequence))
        }
    }
    

    let characters = ("a"..."z").characters  // "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
    let string = ("a"..."z").string          // "abcdefghijklmnopqrstuvwxyz"
    

    let range = ClosedRange.asciiPrintable         // {lowerBound " ", upperBound "~"}   32...126
    let characters = range.characters  // [" ", "!", """, "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~"]
    let string = range.string          // " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
    

    【讨论】:

      【解决方案4】:

      如果你只想要一个已知集合的数组:

      let str = "abcdefghijklmnopqrstuvwxyz"
      let characterArray = Array(str)
      println(characterArray)
      
      //[a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
      

      【讨论】:

      • 好吧,我知道我可以把它打出来,但想知道你将如何像在 C / Obj-C 等中那样映射字符。谢谢
      【解决方案5】:

      使用 Swift 5,您可以使用以下 Playground 示例代码从一系列 Unicode 标量中获取字符数组:

      // 1.
      let unicodeScalarRange: ClosedRange<Unicode.Scalar> = "A" ... "Z"
      // 2.
      let unicodeScalarValueRange: ClosedRange<UInt32> = unicodeScalarRange.lowerBound.value ... unicodeScalarRange.upperBound.value
      // 3.
      let unicodeScalarArray: [Unicode.Scalar] = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
      // 4.
      let characterArray: [Character] = unicodeScalarArray.map(Character.init)
      
      print(characterArray)
      /*
       prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
       */
      
      1. 创建一系列与大写拉丁字母 Unicode 块的代码点匹配的 Unicode 标量。
      2. 由于第一个范围不可跨步(您不能对其进行迭代),因此请使用 Unicode.Scalar 的 value property 将其转换为一系列 Unicode 标量数字表示。
      3. 遍历您的 Unicode 标量数字表示范围,以创建 Unicode 标量数组。
      4. 遍历 Unicode 标量数组以创建字符数组。

      如果您需要从Characters 范围或Strings 范围开始,则可以使用以下示例代码之一:

      let unicodeScalarRange: ClosedRange<Character> = "A" ... "Z"
      let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
      let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
      let characterArray = unicodeScalarArray.map(Character.init)
      
      print(characterArray)
      /*
       prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
       */
      
      let unicodeScalarRange: ClosedRange<String> = "A" ... "Z"
      let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
      let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
      let characterArray = unicodeScalarArray.map(Character.init)
      
      print(characterArray)
      /*
       prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
       */
      

      【讨论】:

        【解决方案6】:

        Swift 5,@Mike S 的补丁

            let aScalars = "a".unicodeScalars
            let aCode = aScalars[aScalars.startIndex].value
            
            let letters: [Character] = (0..<26).map {
                i in
                Character(Unicode.Scalar(aCode + i) ?? aScalars[aScalars.startIndex])
            }
        

        【讨论】:

          【解决方案7】:

          详情

          • Xcode 版本 10.3 (10G8),Swift 5

          解决方案 1

          // MAKR: - ClosedRange extensions
          
          extension ClosedRange where Bound == Unicode.Scalar {
              var representationRange: ClosedRange<UInt32> { return lowerBound.value...upperBound.value }
              var scalars: [Bound] { return representationRange.compactMap(Bound.init) }
          }
          
          extension ClosedRange where Bound == Character {
              var scalars: [Unicode.Scalar]? {
                  guard lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1 else { return nil }
                  return (lowerBound.unicodeScalars.first! ... upperBound.unicodeScalars.first!).scalars
              }
              var all: [Bound]? { return scalars?.map(Character.init) }
          }
          
          extension ClosedRange where Bound == String  {
              var scalars: [Unicode.Scalar]? {
                  guard   lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1,
                          let first = lowerBound.first, let last = upperBound.first else { return nil }
                  return (first...last).scalars
              }
              var all: [Bound]? { return scalars?.map(String.init) }
          }
          
          // MAKR: - Array extensions
          
          extension Array where Element == Character {
              init?(_ range: ClosedRange<Element>) {
                  guard let array = range.all else { return nil }
                  self = array
              }
          }
          
          extension Array where Element == String {
              init?(_ range: ClosedRange<Element>) {
                  guard let array = range.all else { return nil }
                  self = array
              }
          }
          
          extension Array where Element == Unicode.Scalar { init(_ range: ClosedRange<Element>) { self = range.scalars } }
          

          用法1

          func test(value: Any) { print("-- \(type(of: value)) : \(value)") }
          
          print("====================")
          test(value: ("a"..."z").scalars ?? [])
          test(value: ("a"..."z").all ?? [])
          test(value: ("aa"..."z").all ?? [])
          test(value: ("a"..."zz").all ?? [])
          print("====================")
          test(value: (Character("a")...Character("z")).scalars ?? [])
          test(value: (Character("a")...Character("z")).all ?? [])
          print("====================")
          test(value: (Unicode.Scalar("a")...Unicode.Scalar("z")).scalars)
          print("====================")
          test(value: [Unicode.Scalar]("a"..."z"))
          test(value: [Character]("a"..."z") ?? [])
          test(value: [String]("a"..."z") ?? [])
          test(value: [String]("aa"..."z") ?? [])
          test(value: [String]("a"..."zz") ?? [])
          

          使用 1 个日志

          ====================
          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<String> : []
          -- Array<String> : []
          ====================
          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          ====================
          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          ====================
          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<String> : []
          -- Array<String> : []
          

          解决方案 2

          extension Unicode.Scalar: Strideable {
              public typealias Stride = Int
              public func distance(to other: Unicode.Scalar) -> Stride { return abs(Int(value) - Int(other.value)) }
              public func advanced(by n: Stride) -> Unicode.Scalar { return Unicode.Scalar(value + UInt32(n)) ?? self }
          }
          
          extension Character: Strideable {
              public typealias Stride = Int
              public func distance(to other: Character) -> Stride {
                  guard unicodeScalars.count == 1, other.unicodeScalars.count == 1 else { return 0 }
                  return unicodeScalars.first!.distance(to: other.unicodeScalars.first!)
              }
              public func advanced(by n: Stride) -> Character {
                  guard unicodeScalars.count == 1 else { return self }
                  return Character(unicodeScalars.first!.advanced(by: n))
              }
          }
          
          extension Array where Element == String {
              init?(_ range: ClosedRange<Element>) {
                  guard   range.lowerBound.unicodeScalars.count == 1, range.upperBound.unicodeScalars.count == 1,
                          let first = range.lowerBound.unicodeScalars.first, let last = range.upperBound.unicodeScalars.first else { return nil }
                  self = [Unicode.Scalar](first...last).map(String.init)
              }
          }
          

          用法2

          func test(value: Any) { print("-- \(type(of: value)) : \(value)") }
          
          test(value: [Unicode.Scalar]("a"..."z"))
          test(value: [Character]("a"..."z"))
          test(value: [String]("a"..."z"))
          test(value: Array("a"..."z"))
          test(value: Array(Character("a")...Character("z")))
          test(value: Array(Unicode.Scalar("a")...Unicode.Scalar("z")))
          

          使用 2 日志

          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
          -- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
          -- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          -- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
          

          【讨论】:

            【解决方案8】:

            (11...36).map { 字符串($0 - 1, 基数: $0) }

            【讨论】:

            • 欢迎来到 Stack Overflow,请解释为什么这回答了这个问题。
            • 如果有人对这个巧妙的 hack 起作用的原因感兴趣,那是因为 radix 参数将范围内的每个整数转换为该基数。无需改变基数;这是同样的事情,虽然稍微更明显: (10...35).map {String($0, radix: 36)} 所以 0..9 是 0..9,10 是“a”,11 是“ b" 等。它仅适用于 26 个字母小于 36。
            【解决方案9】:

            求解:

            // trying to do something like this (pseudo code):
            // let letters:[Character] = map(0..<26) { i in 'a' + i }
            

            使用 Swift 4.2 / 5.0:

            extension Character: Strideable {
                public typealias Stride = Int
            
                // https://stackoverflow.com/questions/39982335/creating-a-countableclosedrangecharacter
                public func distance(to other: Character) -> Character.Stride {
                    let stride = Int(String(self).unicodeScalars.first!.value) - Int(String(other).unicodeScalars.first!.value)
                    return abs(stride)
                }
            
                public func advanced(by n: Character.Stride) -> Character {
                    return Character(UnicodeScalar(String(self).unicodeScalars.first!.value + UInt32(n))!)
                }
            }
            
            extension ClosedRange where Element == Character {
            
                var characters: [Character] { return Array(self) }
            }
            

            产量:

            let letters: [Character] = ("A"..."Z").characters
            print(letters)
            // ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
            

            【讨论】:

              【解决方案10】:

              这是对@Mike S 答案的一个小改进。 可以简单的获取英文字母中第一个字符的ASCII值,然后迭代如下。

              let aScalars = ("a" as Character).asciiValue!
              
              let letters: [Character] = (0..<26).map {
                 i in Character(UnicodeScalar(aScalars + i))
              }
              

              复杂性

              • 运行时间:O(n)

              • 内存:O(n)

              • 其中 n 是其中的总字母 (Character)

                英文字母。

              【讨论】:

                【解决方案11】:

                您可以简单地使用 let alphabets: [UnicodeScalar] = Array("A"..."Z")

                【讨论】:

                • 这不起作用。它在我的操场上显示错误
                • 您可以使用"A"..."Z" 范围创建从A 到Z 的范围,但Array() 不会返回这些字母的数组
                猜你喜欢
                • 1970-01-01
                • 2017-01-08
                • 2016-02-17
                • 2014-09-29
                • 1970-01-01
                • 2015-05-10
                • 1970-01-01
                • 2019-10-26
                • 1970-01-01
                相关资源
                最近更新 更多