0

Description

I want to format multiple strings so that they are flush with each other. (See actual result and expected result)

what i tried

I have implemented this solution: https://stackoverflow.com/a/31613297/11582550 (See code) It also works, but only if I print the result in the console. I want to save the text in label.text, that doesn't work.

some code

func formattedString(left:String, right:String) -> String {
        let left = (left as NSString).utf8String
        let right = (right as NSString).utf8String
        print(String(format:"%-20s %-20s", left!, right!))
        return String(format:"%-20s %-20s", left!, right!)
    }

label.text += formattedString(left: "Firstname: ", right: "Alfred") + "\n" + formattedString(left:"Lastname: ", right: "LongLastname") + "\n" + formattedString(left:"Note:", right: "private")

// actual result

what i expected

## actual result (saved in label.text)
Firstname:    Alfred
Lastname:    LongLastname
Note:    private

## expected result (saved in label.text)
Firstname:    Alfred
Lastname:     LongLastname
Note:         private
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • It's unclear, expected result & actual result seems to be the same. – Larme May 31 '19 at 11:00
  • 1
    So your problem is that the columns do not align because the font is a proportional font, where different characters can have different width? – Martin R May 31 '19 at 11:03
  • 1
    @vacawama: Thanks for editing -- that's exactly what I meant. –  May 31 '19 at 11:12
  • I think @MartinR identified your problem in his first comment. Choose a fixed space font (such as Courier New) for your label and that should solve your issue. – vacawama May 31 '19 at 11:16
  • @Martin R and vacawama: actually, that solved my problem. Thank you! I will mark the question as answered. –  May 31 '19 at 11:27

2 Answers2

0

Instead of using low-level C functions and C strings (pointer) in Swift, I suggest using pure Swift string manipulation:

func formattedString(left: String, right: String, width: Int = 20) -> String {
    // The `max` call returns 0 if `width - left.count` is negative
    let filler = String(repeating: " ", count: max(0, width - left.count))
    return left + filler + right
}

let result = formattedString(left: "Firstname: ", right: "Alfred") + "\n" + formattedString(left:"Lastname: ", right: "LongLastname") + "\n" + formattedString(left:"Note:", right: "private")
print(result)

// Firstname:          Alfred
// Lastname:           LongLastname
// Note:               private

To cut off long strings, you could do it like this:

func limit(string: String, length: Int) -> String {
    if string.count <= length {
        return string
    }
    return string.prefix(length) + "…"
}
DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • This solves my question, but opens up the next problem with longer inputs that cause a line break. –  May 31 '19 at 11:48
0

Your issue is that you are using a proportional font instead of a fixed-width font for your label. In proportional fonts, the character widths vary, so you can't expect the characters to align.

Change the font that your label is using to a fixed-width font (such as Courier, Courier New, or Menlo) and that will fix your issue.

vacawama
  • 150,663
  • 30
  • 266
  • 294