【问题标题】:How do I use subscript and superscript in Swift?如何在 Swift 中使用下标和上标?
【发布时间】:2015-05-27 08:38:01
【问题描述】:

我希望我的UILabel 以 6.022*1023 的方式显示文本。 Swift对下标和上标有哪些功能?

【问题讨论】:

标签: ios swift


【解决方案1】:

这是我想出的 SwiftUI 文本视图,其中在字符串初始化中嵌入了下标和上标。用 \\b[text]\\e 包围下标,用 \\a[text]\\e 包围上标,其中 [text] 是下标或上标中的字符。

//
//  FormattedText.swift
//
//  Created by Joseph Levy on 8/25/21.
import Foundation

import SwiftUI

enum Attribute { case normal; case sub; case sup }

struct AttributedString {
    var attribute: Attribute
    var string: String
}

func StringToAttributedStrings(_ string: String) -> [AttributedString] {
    //var lastAtt: Attribute = .normal
    var splits = string.components(separatedBy: "\\")
    var filter = false
    var attSplits: [AttributedString] = []
    for i in splits.indices {
        var a: Attribute = { //() -> Attribute in
            let firstchar = splits[i].first
            switch firstchar {
                case  "a": do { a = .sup; filter = true }
                case  "b": do { a = .sub; filter = true }
                case  "e": do { a = .normal; filter = true }
                default: do {
                    a = .normal
                    if i > 0 { splits[i] = "\\" + splits[i] }
                    filter = false;
                }
            }
            return a
        }()
        attSplits.append(AttributedString(attribute: a, string: filter ? String(splits[i].dropFirst()) : splits[i] ))
    }
    return attSplits
}

func FormattedText(_ string: String, up: CGFloat = 8, down: CGFloat = 3) -> Text {
    let aStrings = StringToAttributedStrings(string)
    var returnText = Text("")
    var addedText: Text
    for aString in aStrings {
        switch aString.attribute {
            case .normal: addedText = Text(aString.string)
            case .sub:    addedText = Text(aString.string).font(.footnote).baselineOffset(-down)
            case .sup:    addedText = Text(aString.string).font(.footnote).baselineOffset(up)
        }
        returnText = returnText + addedText
    }
    return returnText
}

使用

FormattedText("Al\\bx\\eGa\\b1-x\\eAs\\a*\\e")

给予

【讨论】:

    【解决方案2】:

    我作为字符串扩展的解决方案

    extension String {
    func setAsSuperscript(_ textToSuperscript: String) -> NSMutableAttributedString {
        let attributedString = NSMutableAttributedString(string: self)
        let foundRange = attributedString.mutableString.range(of: textToSuperscript)
        
        let font = UIFont.systemFont(ofSize: 12)
    
        if foundRange.location != NSNotFound {
            attributedString.addAttribute(.font, value: font, range: foundRange)
            attributedString.addAttribute(.baselineOffset, value: 3, range: foundRange)
            attributedString.addAttribute(.foregroundColor, value: UIColor.red, range: foundRange)
        }
        
        return attributedString
    }
    

    及用法:

    let placeholder = "Required value*".setAsSuperscript("*")
    

    【讨论】:

      【解决方案3】:

      在 SwiftUI 中,可以通过使用 baselineOffset 修饰符来实现上标效果。例如:

                  Text("$")
                      .foregroundColor(Color.white)
                      .font(.custom(AppTheme.getRegularFont(), size: 13))
                      .baselineOffset(8.0)
                  
                  Text("20")
                      .foregroundColor(AppTheme.primaryColor)
                      .font(.custom(AppTheme.getRegularFont(), size: 25))
      

      这是它的外观:

      【讨论】:

        【解决方案4】:

        对于那些使用 SwiftUI 的人,一个选项是在 Text() 中使用 unicode 异常字符串:

        Text("c\u{2082}=a\u{2082}+b\u{2082}") /// c^2 = a^2 + b^2
        

        这种方法的一个好处是更容易内联 subs/supers。

        如果它必须绝对继承自 UILabel(例如,对于本机 NSAttributedString 或本机包装),您可以利用 UIViewRepresentable 并使用 unicode 异常字符串(在大多数情况下应该可以使用)。这是 SO 的一个选项:Stackoverflow。我没试过答案。

        对于那些寻找通用下标和上标(例如算术)的 unicode 的人:

        上标:

        0 = 2070

        1 = 00B9

        2 = 00B2

        3 = 00B3

        4 = 2074

        5 = 2075

        6 = 2076

        7 = 2077

        8 = 2078

        9 = 2079

        + = 207A

        - = 207B

        ( = 207D

        ) = 207E

        n = 207F

        下标:

        0 = 2080

        1 = 2081

        2 = 2082

        3 = 2083

        4 = 2084

        5 = 2085

        6 = 2086

        7 = 2087

        8 = 2088

        9 = 2089

        + = 208A

        - = 208B

        ( = 208D

        ) = 208E

        e = 2091

        n = 2099

        参考:unicode.org

        【讨论】:

          【解决方案5】:

          这会将字符串中的所有数字上标并删除 ^ 字符。

          用途:

          yourstring.addSuper()

          代码:

          extension String {
              func addSuper() -> String {
          
                  let charset = CharacterSet(charactersIn: "1234567890")
          
                  let toSuper: [Character: String] = ["0": "\u{2070}",
                                                      "1": "\u{00B9}",
                                                      "2": "\u{00B2}",
                                                      "3": "\u{00B3}",
                                                      "4": "\u{2074}",
                                                      "5": "\u{2075}",
                                                      "6": "\u{2076}",
                                                      "7": "\u{2077}",
                                                      "8": "\u{2078}",
                                                      "9": "\u{2079}",
                                                      "-": "\u{207B}"]
                  var resultString: String = ""
          
                  var index: Int = 0
          
                  for charater in self {
                      if String(charater).rangeOfCharacter(from: charset) != nil {
                          resultString.append(toSuper[charater] ?? "")
                      } else if charater != "^" {
                          resultString.append(charater)
                      }
                      index += 1
                  }
                  return resultString
              }
          }
          

          【讨论】:

            【解决方案6】:
             extension String {
                func convertToSuperscriptDigits(from start: Int, to end: Int? = nil) - String {
            
                    let end = end ?? self.count
                    let startIndex = self.index(self.startIndex, offsetBy: start)
                    let endIndex = self.index(self.startIndex, offsetBy: end)
                    let replaceRange = startIndex..<endIndex
                    let substring = self[replaceRange]
            
                    let supers = [
                        "0": "\u{2070}",
                        "1": "\u{00B9}",
                        "2": "\u{00B2}",
                        "3": "\u{00B3}",
                        "4": "\u{2074}",
                        "5": "\u{2075}",
                        "6": "\u{2076}",
                        "7": "\u{2077}",
                        "8": "\u{2078}",
                        "9": "\u{2079}"]
            
                    let convertString = substring.map { (char) -> Character in
                        Character(supers[String(char)] ?? String(char))
                    }
            
                    return self.replacingCharacters(in: replaceRange, with: String(convertString))
                }
            

            【讨论】:

            • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
            【解决方案7】:

            这是一个使用递归的 Swift 5.1 解决方案(也应该适用于旧版本的 Swift),它只关注从 Int 输出上标(即没有显示格式)。

            extension Int {
                func superscriptString() -> String {
                    let minusPrefixOrEmpty: String = self < 0 ? Superscript.minus : ""
                    let (quotient, remainder) = abs(self).quotientAndRemainder(dividingBy: 10)
                    let quotientString = quotient > 0 ? quotient.superscriptString() : ""
                    return minusPrefixOrEmpty + quotientString + Superscript.value(remainder)
                }
            }
            
            enum Superscript {
                static let minus = "⁻"
                private static let values: [String] = [
                    "⁰",
                    "¹",
                    "²",
                    "³",
                    "⁴",
                    "⁵",
                    "⁶",
                    "⁷",
                    "⁸",
                    "⁹"
                ]
            
                static func value(_ int: Int) -> String {
                    assert(int >= 0 && int <= 9)
                    return values[int]
                }
            }
            

            这里有一些测试来证明正确性:

             func testPositiveIntegersSuperscript() {
                    XCTAssertEqual(0.superscriptString(), "⁰")
                    XCTAssertEqual(1.superscriptString(), "¹")
                    XCTAssertEqual(2.superscriptString(), "²")
                    XCTAssertEqual(3.superscriptString(), "³")
                    XCTAssertEqual(4.superscriptString(), "⁴")
                    XCTAssertEqual(5.superscriptString(), "⁵")
                    XCTAssertEqual(6.superscriptString(), "⁶")
                    XCTAssertEqual(7.superscriptString(), "⁷")
                    XCTAssertEqual(8.superscriptString(), "⁸")
                    XCTAssertEqual(9.superscriptString(), "⁹")
                    XCTAssertEqual(10.superscriptString(), "¹⁰")
                    XCTAssertEqual(11.superscriptString(), "¹¹")
                    XCTAssertEqual(12.superscriptString(), "¹²")
            
                    XCTAssertEqual(19.superscriptString(), "¹⁹")
                    XCTAssertEqual(20.superscriptString(), "²⁰")
                    XCTAssertEqual(21.superscriptString(), "²¹")
            
                    XCTAssertEqual(99.superscriptString(), "⁹⁹")
                    XCTAssertEqual(100.superscriptString(), "¹⁰⁰")
                    XCTAssertEqual(101.superscriptString(), "¹⁰¹")
                    XCTAssertEqual(102.superscriptString(), "¹⁰²")
            
                    XCTAssertEqual(237.superscriptString(), "²³⁷")
            
                    XCTAssertEqual(999.superscriptString(), "⁹⁹⁹")
                    XCTAssertEqual(1000.superscriptString(), "¹⁰⁰⁰")
                    XCTAssertEqual(1001.superscriptString(), "¹⁰⁰¹")
            
                    XCTAssertEqual(1234.superscriptString(), "¹²³⁴")
                    XCTAssertEqual(1337.superscriptString(), "¹³³⁷")
                }
            
            
                func testNegativeIntegersSuperscript() {
                    XCTAssertEqual(Int(-1).superscriptString(), "⁻¹")
                    XCTAssertEqual(Int(-2).superscriptString(), "⁻²")
                    XCTAssertEqual(Int(-3).superscriptString(), "⁻³")
                    XCTAssertEqual(Int(-4).superscriptString(), "⁻⁴")
                    XCTAssertEqual(Int(-5).superscriptString(), "⁻⁵")
                    XCTAssertEqual(Int(-6).superscriptString(), "⁻⁶")
                    XCTAssertEqual(Int(-7).superscriptString(), "⁻⁷")
                    XCTAssertEqual(Int(-8).superscriptString(), "⁻⁸")
                    XCTAssertEqual(Int(-9).superscriptString(), "⁻⁹")
                    XCTAssertEqual(Int(-10).superscriptString(), "⁻¹⁰")
                    XCTAssertEqual(Int(-11).superscriptString(), "⁻¹¹")
                    XCTAssertEqual(Int(-12).superscriptString(), "⁻¹²")
            
                    XCTAssertEqual(Int(-19).superscriptString(), "⁻¹⁹")
                    XCTAssertEqual(Int(-20).superscriptString(), "⁻²⁰")
                    XCTAssertEqual(Int(-21).superscriptString(), "⁻²¹")
            
                    XCTAssertEqual(Int(-99).superscriptString(), "⁻⁹⁹")
                    XCTAssertEqual(Int(-100).superscriptString(), "⁻¹⁰⁰")
                    XCTAssertEqual(Int(-101).superscriptString(), "⁻¹⁰¹")
                    XCTAssertEqual(Int(-102).superscriptString(), "⁻¹⁰²")
            
                    XCTAssertEqual(Int(-237).superscriptString(), "⁻²³⁷")
            
                    XCTAssertEqual(Int(-999).superscriptString(), "⁻⁹⁹⁹")
                    XCTAssertEqual(Int(-1000).superscriptString(), "⁻¹⁰⁰⁰")
                    XCTAssertEqual(Int(-1001).superscriptString(), "⁻¹⁰⁰¹")
            
                    XCTAssertEqual(Int(-1234).superscriptString(), "⁻¹²³⁴")
                    XCTAssertEqual(Int(-1337).superscriptString(), "⁻¹³³⁷")
                }
            
            

            我的解决方案比gorillaz' solution(基于字符串和数组)快两倍多,这要归功于我的解决方案是基于数学和递归的。这是证据:

              private typealias SuperscriptVector = (value: Int, expectedSuperstring: String)
                private let vector1to9: SuperscriptVector = (123456789, "¹²³⁴⁵⁶⁷⁸⁹")
            
                func performanceTest(times n: Int, function: (Int) -> () -> String) {
                    func manyTimes(_ times: Int) {
                        func doTest(vector: SuperscriptVector) {
                            let result: String = function(vector.value)()
                            XCTAssertEqual(result, vector.expectedSuperstring)
                        }
                        for _ in 0..<times {
                            doTest(vector: vector1to9)
                        }
                    }
            
                    manyTimes(n)
                }
            
                // 3.244 sec
                func testPerformanceMine() {
                    measure {
                        performanceTest(times: 1_000_000, function: Int.superscriptString)
            
                    }
                }
            
            
                // 7.6 sec
                func testPerformanceStackOverflow() {
                    measure {
                        performanceTest(times: 1_000_000, function: Int.superscriptStringArrayBased)
            
                    }
                }
            

            【讨论】:

            • assert(int &gt;= 0 &amp;&amp; int &lt;= 9) 可以更好地表示为assert((0...9).contains(int)),甚至更好地表示为assert(values.indices.contains(int))。但是,如果您还没有包含有用的用户消息,那么这样做是没有意义的,因为它不会为数组下标通常的越界崩溃行为提供任何值。
            【解决方案8】:

            我创建了一个 AmountFormatter 类,它帮助我将十进制数转换为带小数位的数字。

            class AmountFormatter {
            
                static func sharedFormatter(
                    decimalNumber: NSDecimalNumber,
                    currency: String,
                    raisedDecimals: Bool) -> NSAttributedString {
                    let numberFormatter = NumberFormatter()
                    numberFormatter.usesGroupingSeparator = true
                    numberFormatter.groupingSeparator = "."
                    numberFormatter.decimalSeparator = ","
                    numberFormatter.numberStyle = .decimal
            
                    let scale: Int16 = 2
                    let behavior = NSDecimalNumberHandler(
                        roundingMode: .plain,
                        scale: scale,
                        raiseOnExactness: false,
                        raiseOnOverflow: false,
                        raiseOnUnderflow: false,
                        raiseOnDivideByZero: true)
                    guard let amountString = numberFormatter.string(
                        from: decimalNumber.rounding(accordingToBehavior: behavior))
                        else {
                            fatalError("Can't convert conversion from 'NSDecimalNumber' to string")
                    }
                    let currencyAmountString = currency + amountString
            
                    let font = UIFont(name: "Roboto", size: 20)
                    let fontSuper = UIFont(name: "Roboto", size: 10)
                    let attributedCurrencyAmountString = NSMutableAttributedString(
                        string: currencyAmountString,
                        attributes: [.font: font!])
                    if raisedDecimals == false {
                        return attributedCurrencyAmountString as NSAttributedString
                    }
            
                    var array = attributedCurrencyAmountString.string.split(separator: ",")
                    let lenght = array[0].count
                    attributedCurrencyAmountString.setAttributes(
                        [.font: fontSuper!, .baselineOffset: 10],
                        range: NSRange(location: lenght, length: 3))
                    attributedCurrencyAmountString.setAttributes(
                        [.font: fontSuper!],
                        range: NSRange(location: 0, length: 1))
                    return attributedCurrencyAmountString as NSAttributedString
                }
            }
            

            【讨论】:

              【解决方案9】:

              我创建了一个字符串扩展,它接受一个字符串并将其所有上标转换为 unicode 字符。通过这种方式,您可以轻松共享生成的字符串。

              extension Character {
                  var unicode: String {
                      // See table here: https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts
                      let unicodeChars = [Character("0"):"\u{2070}",
                                          Character("1"):"\u{00B9}",
                                          Character("2"):"\u{00B2}",
                                          Character("3"):"\u{00B3}",
                                          Character("4"):"\u{2074}",
                                          Character("5"):"\u{2075}",
                                          Character("6"):"\u{2076}",
                                          Character("7"):"\u{2077}",
                                          Character("8"):"\u{2078}",
                                          Character("9"):"\u{2079}",
                                          Character("i"):"\u{2071}",
                                          Character("+"):"\u{207A}",
                                          Character("-"):"\u{207B}",
                                          Character("="):"\u{207C}",
                                          Character("("):"\u{207D}",
                                          Character(")"):"\u{207E}",
                                          Character("n"):"\u{207F}"]
              
                      if let unicode = unicodeChars[self] {
                          return unicode
                      }
              
                      return String(self)
                  }
              }
              
              extension String {
                  var unicodeSuperscript: String {
                      let char = Character(self)
                      return char.unicode
                  }
              
                  func superscripted() -> String {
                      let regex = try! NSRegularExpression(pattern: "\\^\\{([^\\}]*)\\}")
                      var unprocessedString = self
                      var resultString = String()
              
                      while let match = regex.firstMatch(in: unprocessedString, options: .reportCompletion, range: NSRange(location: 0, length: unprocessedString.count)) {
                              // add substring before match
                              let substringRange = unprocessedString.index(unprocessedString.startIndex, offsetBy: match.range.location)
                              let subString = unprocessedString.prefix(upTo: substringRange)
                              resultString.append(String(subString))
              
                              // add match with subscripted style
                              let capturedSubstring = NSAttributedString(string: unprocessedString).attributedSubstring(from: match.range(at: 1)).mutableCopy() as! NSMutableAttributedString
                              capturedSubstring.string.forEach { (char) in
                                  let superScript = char.unicode
                                  let string = NSAttributedString(string: superScript)
                                  resultString.append(string.string)
                              }
              
                              // strip off the processed part
                              unprocessedString.deleteCharactersInRange(range: NSRange(location: 0, length: match.range.location + match.range.length))
                      }
              
                      // add substring after last match
                      resultString.append(unprocessedString)
                      return resultString
                  }
              
                  mutating func deleteCharactersInRange(range: NSRange) {
                      let mutableSelf = NSMutableString(string: self)
                      mutableSelf.deleteCharacters(in: range)
                      self = mutableSelf as String
                  }
              }
              

              例如"x^{4+n}+12^{3}".superscripted() 产生"x⁴⁺ⁿ+12³"

              这是受到HandyUIKit 的启发,我的代码要点在Github

              【讨论】:

                【解决方案10】:

                一个很好的简单函数,输出一个数字作为上标文本。

                func exponent(i: Int) -> String {
                    let powers : [String] = [
                      "\u{2070}",
                      "\u{00B9}",
                      "\u{00B2}",
                      "\u{00B3}",
                      "\u{2074}",
                      "\u{2075}",
                      "\u{2076}",
                      "\u{2077}",
                      "\u{2078}",
                      "\u{2079}"
                    ]
                
                    let digits = Array(String(i))
                    var string = ""
                
                    for d in digits {
                      string.append("\(powers[Int(String(d))!])")
                    }
                    return string
                }
                

                【讨论】:

                  【解决方案11】:

                  @Atka's Answer 的 Swift 4+ 版本

                  import UIKit
                  
                  extension NSMutableAttributedString {
                      
                      enum Scripting : Int {
                          case aSub = -1
                          case aSuper = 1
                      }
                      
                      func scripts(string: String,
                                    characters: [Character],
                                    type: Scripting,
                                    stringFont: UIFont,
                                    fontSize: CGFloat,
                                    scriptFont: UIFont,
                                    scriptFontSize: CGFloat,
                                    offSet: Int,
                                    length: [Int],
                                    alignment: NSTextAlignment) -> NSMutableAttributedString {
                          
                          let paraghraphStyle = NSMutableParagraphStyle()
                          paraghraphStyle.alignment = alignment
                          
                          var scriptedCharaterLocation = Int()
                          
                          let attributes = [
                                NSAttributedStringKey.font: stringFont,
                                NSAttributedStringKey.foregroundColor: UIColor.black,
                                NSAttributedStringKey.paragraphStyle: paraghraphStyle
                          ]
                          
                          let attString = NSMutableAttributedString(string:string, attributes: attributes)
                          
                          let baseLineOffset = offSet * type.rawValue
                          
                          let scriptTextAttributes: [NSAttributedStringKey : Any] = [
                              NSAttributedStringKey.font: scriptFont,
                              NSAttributedStringKey.baselineOffset: baseLineOffset,
                              NSAttributedStringKey.foregroundColor: UIColor.blue
                          ]
                  
                          for (i,c) in string.enumerated() {
                              
                              for (theLength, aCharacter) in characters.enumerated() {
                                  if c == aCharacter {
                                      scriptedCharaterLocation = i
                                      attString.setAttributes(scriptTextAttributes, range: NSRange(location:scriptedCharaterLocation,
                                                                                                   length: length[theLength]))
                                  }
                              }
                          }
                          return attString
                      }
                  }
                  

                  【讨论】:

                    【解决方案12】:

                    这是一个简单的版本,它具有正确的错误处理并将在 Playground 中编译。

                    import UIKit
                    
                    func setMyLabelText(myLabel: UILabel) {
                        if let largeFont = UIFont(name: "Helvetica", size: 20), let superScriptFont = UIFont(name: "Helvetica", size:10) {
                            let numberString = NSMutableAttributedString(string: "6.022*10", attributes: [.font: largeFont])
                            numberString.append(NSAttributedString(string: "23", attributes: [.font: superScriptFont, .baselineOffset: 10]))
                            myLabel.attributedText = numberString
                        }
                    }
                    
                    let myLabel = UILabel()
                    setMyLabelText(myLabel: myLabel)
                    

                    【讨论】:

                    • 直接使用属性字符串。谢谢。
                    【解决方案13】:

                    大部分答案+示例都在 ObjC 中,但这是在 Swift 中的做法。

                    let font:UIFont? = UIFont(name: "Helvetica", size:20)
                    let fontSuper:UIFont? = UIFont(name: "Helvetica", size:10)
                    let attString:NSMutableAttributedString = NSMutableAttributedString(string: "6.022*1023", attributes: [.font:font!])
                    attString.setAttributes([.font:fontSuper!,.baselineOffset:10], range: NSRange(location:8,length:2))
                    labelVarName.attributedText = attString
                    

                    这给了我:

                    更详细的解释:

                    1. 获取UIFont你想要的默认和上标样式,上标必须更小。
                    2. 使用完整的字符串和默认字体创建NSMutableAttributedString
                    3. 为要更改的字符添加一个属性(NSRange),使用较小的/下标UIFontNSBaselineOffsetAttributeName 的值是您要垂直偏移的量。
                    4. 将其分配给您的UILabel

                    希望这可以帮助其他 Swift 开发人员,因为我也需要这个。

                    【讨论】:

                    • 如果 Helvetica 在点大小为 10 或 20 中不可用,则会崩溃。即使是示例代码也应该使用少量的错误处理来编写。变量名也让人困惑,并且无法编译。
                    【解决方案14】:

                    对于简单易用的 Swift 解决方案,您可能需要查看 HandyUIKit。将其导入您的项目后(例如,通过 Carthage – 请参阅 README 中的说明),您可以执行以下操作:

                    import HandyUIKit
                    
                    "6.022*10^{23}".superscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))
                    

                    此行将返回一个NSAttributedString,它看起来与您要查找的内容一模一样。只需将其分配UILabels attributedText 属性,就是这样!


                    如果您正在寻找下标文本,只需使用subscripted(font:) 代替。它将识别像CO_{2} 这样的结构。如果您想结合两者,还有superAndSubscripted(font:)

                    有关更多信息和其他示例,请参阅docs

                    【讨论】:

                      【解决方案15】:

                      我编写了以下扩展,或者您可以将其用作函数,它对我来说效果很好。你可以通过跳过对你来说不是必需的部分来修改它

                      extension NSMutableAttributedString
                      {
                      enum scripting : Int
                      {
                          case aSub = -1
                          case aSuper = 1
                      }
                      
                      func characterSubscriptAndSuperscript(string:String,
                                                            characters:[Character],
                                                            type:scripting,
                                                            fontSize:CGFloat,
                                                            scriptFontSize:CGFloat,
                                                            offSet:Int,
                                                            length:[Int],
                                                            alignment:NSTextAlignment)-> NSMutableAttributedString
                      {
                          let paraghraphStyle = NSMutableParagraphStyle()
                           // Set The Paragraph aligmnet , you can ignore this part and delet off the function
                          paraghraphStyle.alignment = alignment
                      
                          var scriptedCharaterLocation = Int()
                          //Define the fonts you want to use and sizes
                          let stringFont = UIFont.boldSystemFont(ofSize: fontSize)
                          let scriptFont = UIFont.boldSystemFont(ofSize: scriptFontSize)
                           // Define Attributes of the text body , this part can be removed of the function
                          let attString = NSMutableAttributedString(string:string, attributes: [NSFontAttributeName:stringFont,NSForegroundColorAttributeName:UIColor.black,NSParagraphStyleAttributeName: paraghraphStyle])
                      
                          // the enum is used here declaring the required offset
                          let baseLineOffset = offSet * type.rawValue
                          // enumerated the main text characters using a for loop
                          for (i,c) in string.characters.enumerated()
                          {
                              // enumerated the array of first characters to subscript
                              for (theLength,aCharacter) in characters.enumerated()
                              {
                                  if c == aCharacter
                                  {
                                     // Get to location of the first character
                                      scriptedCharaterLocation = i
                                    //Now set attributes starting from the character above     
                                     attString.setAttributes([NSFontAttributeName:scriptFont,
                                    // baseline off set from . the enum i.e. +/- 1          
                                    NSBaselineOffsetAttributeName:baseLineOffset,
                                    NSForegroundColorAttributeName:UIColor.black],
                                     // the range from above location 
                              range:NSRange(location:scriptedCharaterLocation,
                               // you define the length in the length array 
                               // if subscripting at different location 
                               // you need to define the length for each one
                               length:length[theLength]))
                      
                                  }
                              }
                          }
                          return attString}
                        }
                      

                      例子:

                      let attStr1 = NSMutableAttributedString().characterSubscriptAndSuperscript(
                                     string: "23 x 456", 
                                     characters:["3","5"], 
                                     type: .aSuper, 
                                     fontSize: 20, 
                                     scriptFontSize: 15, 
                                     offSet: 10, 
                                     length: [1,2], 
                                     alignment: .left)
                      

                      let attStr2 = NSMutableAttributedString().characterSubscriptAndSuperscript(
                                 string: "H2SO4", 
                                 characters: ["2","4"], 
                                 type: .aSub, 
                                 fontSize: 20, 
                                 scriptFontSize: 15, 
                                  offSet: 8, 
                                 length: [1,1], 
                                 alignment: .left)
                      

                      【讨论】:

                      • 非常好。我通过添加textColor 参数对其进行了一点扩展。并将UIFont.boldSystemFont 替换为UIFont.systemFont
                      • 我可以看看你的扩展版@Isuru 吗?
                      【解决方案16】:

                      作为一种不同的方法,我编写了一个函数,该函数接受一个字符串,其中指数前面带有^,例如2^2•3•5^2,并返回2²•3•5²

                      func exponentize(str: String) -> String {
                      
                          let supers = [
                              "1": "\u{00B9}",
                              "2": "\u{00B2}",
                              "3": "\u{00B3}",
                              "4": "\u{2074}",
                              "5": "\u{2075}",
                              "6": "\u{2076}",
                              "7": "\u{2077}",
                              "8": "\u{2078}",
                              "9": "\u{2079}"]
                      
                          var newStr = ""
                          var isExp = false
                          for (_, char) in str.characters.enumerate() {
                              if char == "^" {
                                  isExp = true
                              } else {
                                  if isExp {
                                      let key = String(char)
                                      if supers.keys.contains(key) {
                                          newStr.append(Character(supers[key]!))
                                      } else {
                                          isExp = false
                                          newStr.append(char)
                                      }
                                  } else {
                                      newStr.append(char)
                                  }
                              }
                          }
                          return newStr
                      }
                      

                      这是一种蛮力方法,但如果您不想处理属性字符串或者您希望字符串独立于字体,则它可以工作。

                      【讨论】:

                        【解决方案17】:

                        如果您可以处理看起来不完美的文本,并且只需要一部分字符,您可以使用 unicode 上标和下标数字:⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ 这样做的好处是不那么麻烦。

                        【讨论】:

                        • 这样做的另一个好处是,当您有多行时,这不会像在属性字符串中移动基线那样弄乱行距。
                        猜你喜欢
                        • 2015-12-23
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-01-23
                        • 2018-01-09
                        • 2011-01-26
                        • 1970-01-01
                        相关资源
                        最近更新 更多