【问题标题】:Swift: Format String widthSwift:格式化字符串宽度
【发布时间】:2016-11-01 09:08:09
【问题描述】:

我想做的事情在 C/C++、Java 和许多其他语言中非常简单。我想做的就是能够指定字符串的宽度,类似于:

printf("%-15s", var);

这将创建 15 个字符的字段宽度。我做了很多谷歌搜索。我尝试过以各种方式使用COpaquepointerString(format:,但都没有成功。任何建议将不胜感激。谷歌搜索时我可能会错过一些东西。

【问题讨论】:

    标签: swift string format


    【解决方案1】:

    您可以使用withCString 将字符串快速转换为字节数组(技术上是UnsafePointer<Int8>):

    let str = "Hello world"
    let formatted = str.withCString { String(format: "%-15s", $0) }
    
    print("'\(formatted)'")
    

    【讨论】:

    • 你会得到 '("%-15s", 0x00007fcf287884b0)' :-)
    • 不是这样,根据runswiftlang.com 我现在不在 Xcode 附近,所以我无法测试
    • 我会等待另一个确认。不行的话我就删了
    • 如果您导入 Foundation,它应该可以正常工作。
    【解决方案2】:

    你最好自己做

    let str0 = "alpha"
    let length = 20
    // right justify
    var str20r = String(count: (length - str0.characters.count), repeatedValue: Character(" "))
    str20r.appendContentsOf(str0)
    // "               alpha"
    
    // left justify
    var str20l = str0
    str20l.appendContentsOf(String(count: (length - str0.characters.count), repeatedValue: Character(" ")))
    // "alpha               "
    

    如果你需要一些“更通用”的东西

    func formatString(str: String, fixLenght: Int, spacer: Character = Character(" "), justifyToTheRigth: Bool = false)->String {
        let c = str.characters.count
        let start = str.characters.startIndex
        let end = str.characters.endIndex
        var str = str
        if c > fixLenght {
            switch justifyToTheRigth {
            case true:
                let range = start.advancedBy(c - fixLenght)..<end
                return String(str.characters[range])
            case false:
                let range = start..<end.advancedBy(fixLenght - c)
                return String(str.characters[range])
            }
        } else {
            var extraSpace = String(count: fixLenght - c, repeatedValue: spacer)
            if justifyToTheRigth {
                extraSpace.appendContentsOf(str)
                return extraSpace
            } else {
                str.appendContentsOf(extraSpace)
                return str
            }
        }
    }
    
    let str = "ABCDEFGH"
    let s0 = formatString(str, fixLenght: 3)
    let s1 = formatString(str, fixLenght: 3, justifyToTheRigth: true)
    let s2 = formatString(str, fixLenght: 10, spacer: Character("-"))
    let s3 = formatString(str, fixLenght: 10, spacer: Character("-"), justifyToTheRigth: true)
    
    print(s0)
    print(s1)
    print(s2)
    print(s3)
    

    打印出来的

    ABC
    FGH
    ABCDEFGH--
    --ABCDEFGH
    

    【讨论】:

      【解决方案3】:

      问题在于 Swift 字符串具有可变大小的元素,因此“15 个字符”是什么是模棱两可的。这对于简单的字符串来说是一个令人沮丧的根源——但在处理表情符号、区域标识符、连字等时会使语言更加精确。

      您可以将 Swift 字符串转换为 C 字符串并使用普通格式化程序(请参阅 Santosh 的回答)。处理字符串的“Swift”方式是从Characters 集合的起始索引开始,前进N 次。例如:

      let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      
      let index = alphabet.characters.startIndex.advancedBy(14) // String.CharacterView.Index
      let allChars = alphabet.characters.prefixThrough(index) // String.CharacterView
      
      print(String(allChars)) // "ABCDEFGHIJKLMNO\n"
      

      如果你想强制填充,你可以使用这样的方法:

      extension String {
          func formatted(characterCount characterCount:Int) -> String {
              if characterCount < characters.count {
                  return String(characters.prefixThrough(characters.startIndex.advancedBy(characterCount - 1)))
              } else {
                  return self + String(count: characterCount - characters.count, repeatedValue: " " as Character)
              }
          }
      }
      
      let abc = "ABC"
      let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      
      print("!\(abc.formatted(characterCount: 15))!")
      // "!ABC            !\n"
      
      print("!\(alphabet.formatted(characterCount: 15))!")
      // "!ABCDEFGHIJKLMNOP!\n"
      

      【讨论】:

      • 如果字符串短于 15 个字符,会填充它吗?
      • @AlexCauthen 不,它会崩溃,因为你会超过字符串中的字符数。这只是一个简单的例子,说明如何在 Swift 中处理字符串长度。
      • @AlexCauthen 我用一个字符串扩展更新了我的答案,可能会做你想做的事
      【解决方案4】:

      你试过了吗?

      let string1 = "string1"
      let string2 = "string2"
      let formattedString = String(format: "%-15s - %s",
                   COpaquePointer(string1.cStringUsingEncoding(NSUTF8StringEncoding)!),
                   COpaquePointer(string2.cStringUsingEncoding(NSUTF8StringEncoding)!)
      )
      
      print(formattedString)
      //string1         - string2
      

      【讨论】:

      【解决方案5】:

      我们现在有很多有趣的答案。谢谢大家。我写了以下内容:

      func formatLeftJustifiedWidthSpecifier(stringToChange: String, width: Int) -> String {
      
          var newString: String = stringToChange
          newString = newString.stringByPaddingToLength(width, withString: " ", startingAtIndex: 0)
          return newString
      }
      

      【讨论】:

      • 几个问题:(1)你正在桥接 NSString,所以你失去了 Swift 字符串的好处,(2)为什么要写这个而不是直接调用 stringByPaddingToLength? , (3) : String 是不必要的, (4) 为什么分配给newString 只是为了立即覆盖值?
      • 我没有意识到它可以连接到 NSString。谢谢你让我知道。如果我创建一个函数,我可以从任何地方调用它以避免代码重复。我来自明确定义我的类型的背景,所以这确实是一种风格。在 Swift 3.0 及更高版本中,函数参数被定义为 let 常量,因此需要一个局部变量来进行修改。
      【解决方案6】:

      一方面 %@ 用于格式化字符串对象:

      import Foundation
      
      var str = "Hello"
      print(String(format: "%@", str))
      

      但它不支持宽度修饰符:

      print(String(format: "%-15@", str))
      

      仍会打印未填充的文本:

      "Hello\n"
      

      但是有一个修饰符 %s 似乎可以与 CStrings 一起使用:

      var cstr = (str as NSString).utf8String //iOS10+ or .UTF8String otherwise
      
      print(String(format: "%-15s", cstr!))
      

      输出:

      "Hello          \n"
      

      一件好事是您可以使用与 NSLog 相同的格式规范:

      NSLog("%-15s", cstr!)
      

      【讨论】:

      • 'NSString' 没有成员 'utf8String'
      • 是的,试试UTF8String,好像在iOS10里换成了小写前缀。
      猜你喜欢
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-28
      • 2017-07-07
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多