Darrell Root
Darrell Root

Reputation: 844

SwiftUI Text View does not show non-displayable characters

I have Swift code which parses an LLDP (link layer discovery protocol) frame, including a field that can be arbitrarily vendor-defined. Sometimes it's a String. Sometimes its an arbitrary data structure.

Here's how I take the data and force it into a String with .utf8 encoding.

        let ouiString = String(data: data[data.startIndex + 6 ..< data.startIndex + 2 + tlvLength], encoding: .utf8) ?? ""

Here's the resulting data structure (part of an enumeration with an associated value). "ouiString" above is now in the "info: String" field at the end.

case ouiSpecific(oui: String, subType: Int, info: String)

Here's how I generate a description:

    case .ouiSpecific(let oui, let subType, let info):
        return "OUI \(oui) subType \(subType) \(info)"

Here's an example of the description where the original data was not a String. The non-displayable characters are shown in a way I find acceptable.

(lldb) po value.description
"OUI 00:12:0f subType 5 \0\u{11}\0\u{11}\0\u{11}\0\u{11}\0\u{11}"

Here's how I try to display it in a SwiftUI List:

        List(lldp.values, id: \.self) { value in
            Text(value.description)
        }

And here's an image of the resulting display in SwiftUI. The info field with all the escaped non-displayable characters are not shown.

SwiftUI List Output

How can I display the field in a SwiftUI Text View with the non-displayable characters escaped like in the "po" output?

Upvotes: 3

Views: 712

Answers (1)

Leo Dabus
Leo Dabus

Reputation: 236568

You can use Unicode.Scalar method escaped(asASCII: Bool) to convert unprintable characters to string:

func escaped(asASCII forceASCII: Bool) -> String

Scalar values representing characters that are normally unprintable or that otherwise require escaping are escaped with a backslash.

extension StringProtocol {
    var asciiEscaped: String {
        unicodeScalars.map{$0.escaped(asASCII: true)}.joined()
    }
}

Playground testing:

let str = "\0\u{11}\0\u{11}\0\u{11}\0\u{11}\0\u{11}"
print(str.asciiEscaped)

This will print:

\0\u{11}\0\u{11}\0\u{11}\0\u{11}\0\u{11}

Upvotes: 3

Related Questions