Roger
Roger

Reputation: 4797

Transform an NSAttributedString to plain text

I have an instance of NSData containing attributed text (NSAttributedString) originating from an NSTextView. I want to convert the attributed string to a plain string (NSString) without any formatting to do some text analysis (at the moment of conversion I do not have access to the originating NSTextView nor its NSTextStorage instance).

What would be the best way to do this?

EDIT:

Out of curiosity I examined the result of:

[[[self textView] textStorage] words]

which appeared to be a handy thing for doing some text analysis. The resulting array contains instances of NSSubTextStorage (example below of the word "Eastern"):

Eastern{ NSFont = "\"LucidaGrande 11.00 pt. P [] (0x7ffcaae08330) fobj=0x10a8472d0, spc=3.48\""; NSParagraphStyle = "Alignment 0, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n
140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n
308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningFactor 0.05, HeaderLevel 0"; }

NSSubTextStorage is probably a private class as I could not find any documentation for it. It also retains all formatting.

Upvotes: 45

Views: 37620

Answers (5)

ConfusionTowers
ConfusionTowers

Reputation: 961

To expand slightly on @Juguang's answer:

extension AttributedString {
    func toString() -> String {
        return self.characters.map { String($0) }.joined(separator: "")
    }
}

Usage:

print("Working value = \(workingAttribStrng.toString())")

Current Swift (as of December 2024, Xcode 16.1, Swift 5.10) won't accept the earlier answers, but this seems to work fine, and this thread is what comes up first when searching for "Swift AttributedString to plaintext".

Upvotes: 0

Juguang
Juguang

Reputation: 651

As of Swift 5.7 (or maybe earlier), the new AttributedString struct no longer has a string property. The code below works, even looking silly.

part.characters.map { String($0) }.joined(separator: "")

Upvotes: 3

Justin Vallely
Justin Vallely

Reputation: 6089

Updating for Swift 5:

attributedText.string

Upvotes: 32

Imanou Petit
Imanou Petit

Reputation: 92419

With Swift 5 and macOS 10.0+, NSAttributedString has a property called string. string has the following declaration:

var string: String { get }

The character contents of the receiver as an NSString object.

Apple also states about string:

Attachment characters are not removed from the value of this property. [...]


The following Playground code shows how to use NSAttributedString's string property in order to retrieve the string content of an NSAttributedString instance:

import Cocoa

let string = "Some text"
let attributes = [NSAttributedString.Key.underlineStyle : NSUnderlineStyle.single]
let attributedString = NSAttributedString(string: string, attributes: attributes)

/* later */

let newString = attributedString.string
print(newString) // prints: "Some text"
print(type(of: newString)) // prints: String

Upvotes: 4

CRD
CRD

Reputation: 53000

If I understand you correctly you have an NSData, say data, containing an encoded NSAttributedString. To reverse the process:

NSAttributedString *nas = [[NSAttributedString alloc] initWithData:data
                                                           options:nil
                                                documentAttributes:NULL
                                                             error:NULL];

and to get the plain text without attributes you then do:

NSString *str = [nas string];

Upvotes: 70

Related Questions