How do I use subscript and superscript in Swift?

IosSwift

Ios Problem Overview


I want my UILabel to display text in following manner 6.022*1023. What functions does Swift have for subscript and superscript?

Ios Solutions


Solution 1 - Ios

Most of the answers+examples are in ObjC, but this is how to do it in 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

This gives me:

SuperScript Example

In a more detailed explanation:

  1. Get UIFont you want for both the default and superscript style, superscript must be smaller.
  2. Create a NSMutableAttributedString with the full string and default font.
  3. Add an attribute to the characters you want to change (NSRange), with the smaller/subscript UIFont, and the NSBaselineOffsetAttributeName value is the amount you want to offset it vertically.
  4. Assign it to your UILabel

Hopefully this helps other Swift devs as I needed this as well.

Solution 2 - Ios

As a different approach, I wrote a function that takes in a string where the exponents are prepended with ^ such as 2^2•3•5^2 and returns 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
}

It's a bit of a brute force method, but it works if you don't want to deal with attributed strings or you want your string to be independent of a font.

Solution 3 - Ios

If you can get along with text that doesn't look perfect, and only need a subset of characters you can make use of the unicode superscript and subscript numbers: ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ This has the advantage of being a lot less cumbersome.

Solution 4 - Ios

I wrote the following extension or you can use it as a function, it is working well for me . you can modify it by skipping the parts that are not essential to you

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}
  }

examples:

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

enter image description here

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

enter image description here

Solution 5 - Ios

For a simple to use Swift solution, you might want to checkout HandyUIKit. After importing it into your project (e.g. via Carthage – see instructions in README) you can do something like this:

import HandyUIKit

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

This line will return an NSAttributedString which will look exactly like what you're looking for. Just assign it to a UILabels attributedText property and that's it!


If you're looking for subscripting a text, simply use subscripted(font:) instead. It will recognize structures like CO_{2}. There's also superAndSubscripted(font:) if you want to combine both.

See the docs for more information and additional examples.

Solution 6 - Ios

Here is a simple version that has correct error handling and will compile in 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)

Solution 7 - Ios

Swift 4+ Version of @Atka's Answer

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
    }
}

Solution 8 - Ios

Here's a Swift 5.1 solution (should work with older versions of Swift too) using recursion, that only focuses outputting a superscript from an Int (i.e. no formatting for display).

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]
    }
}

Here are some tests to prove correctness:

 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(), "⁻¹³³⁷")
    }

My solution is more than twice as fast as gorillaz' solution(which is string and array based), thanks to mine being math and recursion based. Here is proof:

  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)

        }
    }

Solution 9 - Ios

My solution as an extension of String

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
}

And usage:

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

Solution 10 - Ios

For those using SwiftUI, an option is to use a unicode exception string in Text():

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

One benefit of this method is easier inline subs/supers.

If it must absolutely inherit from UILabel (e.g. for native NSAttributedString or native wrapping), you can leverage UIViewRepresentable and use the unicode exception string (which should work in most cases). Here is an option on SO: Stackoverflow. I have not tried the answer.

And for those looking for unicode for common subscripts and superscripts (e.g. for arithmetic):

Superscripts:

> 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

Subscripts:

> 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

Reference: unicode.org

Solution 11 - Ios

A nice simple function that outputs a number as the superscript text.

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
}




Solution 12 - Ios

In SwiftUI it is possible to achieve superscript effect by using baselineOffset modifier. For example:

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

Here is how it looks:

enter image description here

Solution 13 - Ios

I have created a String extension which takes a string and converts all of its superscript into unicode characters. This way you could for example share the resulting string without any hassle.

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
    }
}

For example "x^{4+n}+12^{3}".superscripted() produces "x⁴⁺ⁿ+12³"

This was inspired by HandyUIKit and the gist to my code is on Github

Solution 14 - Ios

I created an AmountFormatter class which helped me convert decimal numbers into numbers with raised decimals.

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
    }
}

Solution 15 - Ios

 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))
    }

Solution 16 - Ios

This will superscript all the numbers in a string and remove the ^ character.

Use:

yourstring.addSuper()

code:

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
    }
}

Solution 17 - Ios

Here is what I came up with for a SwiftUI Text view with subscripts and superscripts embedded in the String initialize. Surround a subscript with \\b[text]\\e and a superscript with \\a[text]\\e where [text] are the characters in the sub- or superscript.

//
//  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
}

Use

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

gives

Text View on Screen

Solution 18 - Ios

I wrote a fun little algorithm for this as an extension on Int that doesn't require any messy attributed strings.

Usage:

let superscriptString = 8675309.superscriptString

Implementation:

extension Int {
    
    var superscriptString: String {

        var input: Int = self
        var result: String = ""
        
        while input > 0 {
            let lastDigit = input % 10
            input /= 10
            guard let superscript = lastDigit.superscript else { continue }
            result = superscript + result
        }
        
        return result
    }
    
    private var superscript: String? {
        switch self {
        case 0:
            return "\u{2070}"
        case 1:
            return "\u{00B9}"
        case 2:
            return "\u{00B2}"
        case 3:
            return "\u{00B3}"
        case 4:
            return "\u{2074}"
        case 5:
            return "\u{2075}"
        case 6:
            return "\u{2076}"
        case 7:
            return "\u{2077}"
        case 8:
            return "\u{2078}"
        case 9:
            return "\u{2079}"
        default:
            return nil
        }
    }
    
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdam YoungView Question on Stackoverflow
Solution 1 - IosForrest PorterView Answer on Stackoverflow
Solution 2 - IosChrisView Answer on Stackoverflow
Solution 3 - IosGlenn HowesView Answer on Stackoverflow
Solution 4 - IosAtkaView Answer on Stackoverflow
Solution 5 - IosJeehutView Answer on Stackoverflow
Solution 6 - IosSafeFastExpressiveView Answer on Stackoverflow
Solution 7 - IosAbhishek ThapliyalView Answer on Stackoverflow
Solution 8 - IosSajjonView Answer on Stackoverflow
Solution 9 - IosrastislvView Answer on Stackoverflow
Solution 10 - Iosuser1909186View Answer on Stackoverflow
Solution 11 - IosgorillazView Answer on Stackoverflow
Solution 12 - Iosselma.suvalijaView Answer on Stackoverflow
Solution 13 - Ioshenrik-dmgView Answer on Stackoverflow
Solution 14 - IossejmyView Answer on Stackoverflow
Solution 15 - IosMikhail YaskouView Answer on Stackoverflow
Solution 16 - IosaaronmbmorseView Answer on Stackoverflow
Solution 17 - IosJoseph LevyView Answer on Stackoverflow
Solution 18 - IosswiftyboiView Answer on Stackoverflow