How do I remove the last two lines of this NSAttributedString?
NSString *exampleString = #"line 1\nline 2\nline 3\nline 4"
NSAttributedString *as = [NSAttributedString alloc] int];
[as setString:exampleString];
[self removeLastTwoLinesOfAttributedString:as];
NSLog(#"%#",as);
-(void)removeLastTwoLinesOfAttributedString:(NSAttributedString *)string {
//some code here
}
I'd like to end up with #"line 1\nline 2" in this example. Thanks
You could do something like this :
-(NSAttributedString *) removeLastTwoLinesOfAttributedString:(NSAttributedString *aString) {
NSRange range = [aString.string rangeOfString:#"\n" options:NSBackwardsSearch];
range = [aString.string rangeOfString:#"\n" options:NSBackwardsSearch range:NSMakeRange(0, range.location)];
return [aString attributedSubstringFromRange:NSMakeRange(0, range.location)];
}
int main (int argc, const char * argv[])
{
NSString *exampleString = #"line 1\nline 2\nline 3\nline 4";
NSAttributedString *as = [[NSAttributedString alloc] initWithString:exampleString];
as = [self removeLastTwoLinesOfAttributedString:as];
NSLog(#"%#",as);
return 0;
}
Output
line 1
line 2
I would suggest as the best solution:
-(NSAttributedString *)removeLastTwoLinesOfAttributedString:(NSAttributedString *)aString {
if (aString.length == 0) {
return aString
}
NSString *string = [aString string];
unsigned numberOfLines, index, stringLength = [string length];
NSRange rangeOfLastTwoLines = NSMakeRange(aString.length - 1, 0);
for (index = stringLength-1, numberOfLines = 0; index >= 0 && numberOfLines < 2; numberOfLines++) {
NSRange rangeOfLine = [string lineRangeForRange:NSMakeRange(index, 0)];
rangeOfLastTwoLines = NSUnionRange(rangeOfLastTwoLines, rangeOfLine);
index -= rangeOfLine.length;
}
return [aString attributedSubstringFromRange:NSMakeRange(0, rangeOfLastTwoLines.location)];
}
This has the benefit of working with any newline character not just "\n" and it uses the preferred by Apple method for detecting lines see this
Also it will not break if the last two lines are less than 2
If you're using Swift you can do this, if you're using Objective-C you should look at the other answers.
You can drop the last two lines of a String like this
string.components(separatedBy: "\n").dropLast(2).joined(separator: "\n")
To do it to an attributed string just access the string property, remove the last two lines, and create an attributed string with the trimmed string and all the same attributes.
There is a substring that occurs in a string several times. I use rangeOfString, but it seems that it can only find the first location. How can I find all the locations of the substring?
NSString *subString1 = #"</content>";
NSString *subString2 = #"--\n";
NSRange range1 = [newresults rangeOfString:subString1];
NSRange range2 = [newresults rangeOfString:subString2];
int location1 = range1.location;
int location2 = range2.location;
NSLog(#"%i",location1);
NSLog(#"%i",location2);
You can use rangeOfString:options:range: and set the third argument to be beyond the range of the first occurrence. For example, you can do something like this:
NSRange searchRange = NSMakeRange(0,string.length);
NSRange foundRange;
while (searchRange.location < string.length) {
searchRange.length = string.length-searchRange.location;
foundRange = [string rangeOfString:substring options:0 range:searchRange];
if (foundRange.location != NSNotFound) {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location+foundRange.length;
} else {
// no more substring to find
break;
}
}
Swift 3.0
Find all locations of substring i
let text = "This is the text and i want to replace something"
let mutableAttributedString = NSMutableAttributedString(string: text)
var searchRange = NSRange(location: 0, length: text.characters.count)
var foundRange = NSRange()
while searchRange.location < text.characters.count {
searchRange.length = text.characters.count - searchRange.location
foundRange = (text as NSString).range(of: "i", options: NSString.CompareOptions.caseInsensitive, range: searchRange)
if foundRange.location != NSNotFound {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location + foundRange.length
mutableAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: foundRange)
}
else {
// no more substring to find
break
}
}
//Apply
textLabel.attributedText = mutableAttributedString;
And this output-
This is my solution. Basically, the algorithm traverses the string looking for substring matches and returns those matches in an array.
Since an NSRange is a struct it cannot be added to the array directly. By using NSValue, I can encode the match first and then add it to the array. To retrieve the range, I then decode the NSValue object to an NSRange.
#import <Foundation/Foundation.h>
NSRange makeRangeFromIndex(NSUInteger index, NSUInteger length) {
return NSMakeRange(index, length - index);
}
NSArray<NSValue *> * allLocationsOfStringMatchingSubstring(NSString *text, NSString *pattern) {
NSMutableArray *matchingRanges = [NSMutableArray new];
NSUInteger textLength = text.length;
NSRange match = makeRangeFromIndex(0, textLength);
while(match.location != NSNotFound) {
match = [text rangeOfString:pattern options:0L range:match];
if (match.location != NSNotFound) {
NSValue *value = [NSValue value:&match withObjCType:#encode(NSRange)];
[matchingRanges addObject:value];
match = makeRangeFromIndex(match.location + 1, textLength);
}
}
return [matchingRanges copy];
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *text = #"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG";
NSString *pattern = #"CAT";
NSArray<NSValue *> *matches = allLocationsOfStringMatchingSubstring(text, pattern);
NSLog(#"Text: %#", text);
NSLog(#"Pattern: %#", pattern);
NSLog(#"Number of matches found: %li", matches.count);
[matches enumerateObjectsUsingBlock:^(NSValue *obj, NSUInteger idx, BOOL *stop) {
NSRange match;
[obj getValue:&match];
NSLog(#" Match found at index: %li", match.location);
}];
}
return 0;
}
Passing nil to [string rangeOfString:substring options:nil range:searchRange]; shows a warning.
To get rid of the warning, put in an enum from this group
enum {
NSCaseInsensitiveSearch = 1,
NSLiteralSearch = 2,
NSBackwardsSearch = 4,
NSAnchoredSearch = 8,
NSNumericSearch = 64,
NSDiacriticInsensitiveSearch = 128,
NSWidthInsensitiveSearch = 256,
NSForcedOrderingSearch = 512,
NSRegularExpressionSearch = 1024
};
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/doc/constant_group/Search_and_Comparison_Options
Here is a version in Swift 2.2 of PengOne's answer with input from kevinlawler and Gibtang
Note: string and substring are of type NSString
let fullStringLength = (string as String).characters.count
var searchRange = NSMakeRange(0, fullStringLength)
while searchRange.location < fullStringLength {
searchRange.length = fullStringLength - searchRange.location
let foundRange = string.rangeOfString(substring as String, options: .CaseInsensitiveSearch, range: searchRange)
if foundRange.location != NSNotFound {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location + 1
} else {
// no more strings to find
break
}
}
I suggest using regular expression because it's a more declarative way and has fewer lines of code to write.
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"%#" options:nil error:nil];
NSString *toSearchStr = #"12312 %# Text %# asdsa %#";
__block int occurs = 0;
[regex enumerateMatchesInString:toSearchStr options:0 range:NSMakeRange(0, toSearchStr.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
occurs++;
}];
// occurs == 3
I have an example NSString in iOS
NSString* str = #"-- This is an example string";
I want to get the first alphabet letter. The result of above situation is letter "T" from word "This". Some characters before letter "T" is not alphabet letter so it returns the first alphabet letter is "T".
How can I retrieve it? If the string not contain any alphabet letter, it can return nil.
Besides, the result can be a NSRange
NSRange range = [string rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
First create a NSCharecterSet as a global variable and write this code
-(void)viewDidLoad{
NSCharacterSet *s = [NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
s = [s invertedSet];
NSString *myString = #"--- This is a string";
NSArray *arrayOfStrings = [myString componentsSeparatedByString:#" "];
for(int i=0;i<arrayOfStrings.count){
NSString *current = [arrayOfStrings objectAtIndex:i];
char c = [self returnCharacter:current];
if(c == nil){
//that means first word is not with alphabets;
}
else {
NSLog(#"%c",c);
//your output.
}
}
}
And here is the method
-(char)returnChracter:(NSString*)string{
NSRange r = [string rangeOfCharacterFromSet:s];
if (r.location != NSNotFound) {
NSLog(#"the string contains illegal characters");
return nil;
}
else {
//string contains all alphabets
char firstLetter = [string charAtIndex:0];
return firstLetter;
}
}
You can use the following function. Pass a string and get first character as a string.
-(NSString*)getFirstCharacter:(NSString*)string
{
for(int i=0;i<string.length;i++)
{
unichar firstChar = [string characterAtIndex:i];
NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
if ([letters characterIsMember:firstChar]) {
return [NSString:stringWithFormat:#"%c",firstChar];
}
}
return nil;
}
How to display hyphen with UILabel like this, - A I origine - , Here I use the string appending method. I get this type of output - À l'origine de la guerre -. But I want display hyphen before the starting point of text and display hyphen after 10 charatcers.
I was searched but i can't get valied source. kindly give any suggestion if you know.
NSString *tempStr = #" - ";
tempStr = [tempStr stringByAppendingString:NSLocalizedString(#"OriginallyWar", #"")];
tempStr = [tempStr stringByAppendingString:#" -"];
[headingLabel setText:tempStr];
[headingLabel setFont:MRSEAVES_BOLD(17)];
Use NSMutableString and insert characters,
[yourString insertString:#"-" atIndex:10];
if you are using StoryBoard directly set it to the text property on Attribute inspector. Put 10 empty spaces after the end of character and the -.
You may try this code
NSString *inputString = #"OriginallyWarDFdfsdfdDFSDfdsfdsfDFdsfadsfawerdsaf";
NSMutableString *localizedInputString = [NSMutableString stringWithString:NSLocalizedString(inputString, #"")];
int numberOfCharacters = localizedInputString.length;
int numberOf10s = (numberOfCharacters/10 + 1);
int numberOfCharactersToBeInserted = 0;
for (int i = 1; i < numberOf10s; i++) {
int characterIndex = (i * 10) + numberOfCharactersToBeInserted;
if (i == (numberOf10s - 1) && numberOfCharacters % 10 == 0) {
[localizedInputString insertString:#" -" atIndex:characterIndex];
numberOfCharactersToBeInserted = 2 * i;
} else {
[localizedInputString insertString:#" - " atIndex:characterIndex];
numberOfCharactersToBeInserted = 3 * i;
}
}
if (numberOfCharacters == 0) {
[localizedInputString insertString:#"-" atIndex:0];
} else {
[localizedInputString insertString:#"- " atIndex:0];
}
NSLog(#"localizedInputString : %#", localizedInputString);
try using NSMutableString
NSString *tempStr = #" - ";
tempStr = [tempStr stringByAppendingString:NSLocalizedString(#"OriginallyWar", #"")];
NSMutableString *tempStrMutable=[[NSMutableString alloc]initWithString:tempStr];
[tempStrMutable insertString:#"-" atIndex:10];
[headingLabel setText:tempStrMutable];
Is there a way to HTML encode a string (NSString) in Objective-C, something along the lines of Server.HtmlEncode in .NET?
There isn't an NSString method that does that. You'll have to write your own function that does string replacements. It is sufficient to do the following replacements:
'&' => "&"
'"' => """
'\'' => "'"
'>' => ">"
'<' => "<"
Something like this should do (haven't tried):
[[[[[myStr stringByReplacingOccurrencesOfString: #"&" withString: #"&"]
stringByReplacingOccurrencesOfString: #"\"" withString: #"""]
stringByReplacingOccurrencesOfString: #"'" withString: #"'"]
stringByReplacingOccurrencesOfString: #">" withString: #">"]
stringByReplacingOccurrencesOfString: #"<" withString: #"<"];
I took Mike's work and turn it into a category for NSMutableString and NSString
Make a Category for NSMutableString with:
- (NSMutableString *)xmlSimpleUnescape
{
[self replaceOccurrencesOfString:#"&" withString:#"&" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#""" withString:#"\"" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"'" withString:#"'" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"'" withString:#"'" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"" withString:#"'" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"" withString:#"-" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#">" withString:#">" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"<" withString:#"<" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
return self;
}
- (NSMutableString *)xmlSimpleEscape
{
[self replaceOccurrencesOfString:#"&" withString:#"&" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"\"" withString:#""" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"'" withString:#"'" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#">" withString:#">" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
[self replaceOccurrencesOfString:#"<" withString:#"<" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
return self;
}
Make a Category for NSString with:
- (NSString *)xmlSimpleUnescapeString
{
NSMutableString *unescapeStr = [NSMutableString stringWithString:self];
return [unescapeStr xmlSimpleUnescape];
}
- (NSString *)xmlSimpleEscapeString
{
NSMutableString *escapeStr = [NSMutableString stringWithString:self];
return [escapeStr xmlSimpleEscape];
}
* A Swift 2.0 Version *
The Objective-C version is a little more efficient as it does mutable operations on the string. However, this is a swift way to do simple escaping:
extension String
{
typealias SimpleToFromRepalceList = [(fromSubString:String,toSubString:String)]
// See http://stackoverflow.com/questions/24200888/any-way-to-replace-characters-on-swift-string
//
func simpleReplace( mapList:SimpleToFromRepalceList ) -> String
{
var string = self
for (fromStr, toStr) in mapList {
let separatedList = string.componentsSeparatedByString(fromStr)
if separatedList.count > 1 {
string = separatedList.joinWithSeparator(toStr)
}
}
return string
}
func xmlSimpleUnescape() -> String
{
let mapList : SimpleToFromRepalceList = [
("&", "&"),
(""", "\""),
("'", "'"),
("'", "'"),
("", "'"),
("", "-"),
(">", ">"),
("<", "<")]
return self.simpleReplace(mapList)
}
func xmlSimpleEscape() -> String
{
let mapList : SimpleToFromRepalceList = [
("&", "&"),
("\"", """),
("'", "'"),
(">", ">"),
("<", "<")]
return self.simpleReplace(mapList)
}
}
I could have used the NSString bridging capabilities to write something very similar to the NSString version, but I decided to do it more swifty.
I use Google Toolbox for Mac (works on iPhone). In particular, see the additions to NSString in GTMNSString+HTML.h and GTMNSString+XML.h.
For URL encoding:
NSString * encodedString = [originalString
stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
See Apple's NSString documentation for more info.
For HTML encoding:
Check out CFXMLCreateStringByEscapingEntities, which is part of the Core Foundation XML library, but should still do the trick.
the samets's routine forgot the hex digit. Here's the routine I came up with that works:
- (NSString*)convertEntities:(NSString*)string
{
NSString *returnStr = nil;
if( string )
{
returnStr = [ string stringByReplacingOccurrencesOfString:#"&" withString: #"&" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#""" withString:#"\"" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#"'" withString:#"'" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#"9" withString:#"'" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#"" withString:#"'" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#"" withString:#"'" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#">" withString:#">" ];
returnStr = [ returnStr stringByReplacingOccurrencesOfString:#"<" withString:#"<" ];
returnStr = [ [ NSString alloc ] initWithString:returnStr ];
}
return returnStr;
}
If you can use NSXMLNode (on OS X) Here is the trick:
NSString *string = #"test<me>"
NSXMLNode *textNode = [NSXMLNode textWithStringValue:string];
NSString *escapedString = [textNode.XMLString];
Swift 4
extension String {
var xmlEscaped: String {
return replacingOccurrences(of: "&", with: "&")
.replacingOccurrences(of: "\"", with: """)
.replacingOccurrences(of: "'", with: "'")
.replacingOccurrences(of: ">", with: ">")
.replacingOccurrences(of: "<", with: "<")
}
}
Here is a more efficient implementation of this xml escape logic.
+ (NSString*) xmlSimpleEscape:(NSString*)unescapedStr
{
if (unescapedStr == nil || [unescapedStr length] == 0) {
return unescapedStr;
}
const int len = [unescapedStr length];
int longer = ((int) (len * 0.10));
if (longer < 5) {
longer = 5;
}
longer = len + longer;
NSMutableString *mStr = [NSMutableString stringWithCapacity:longer];
NSRange subrange;
subrange.location = 0;
subrange.length = 0;
for (int i = 0; i < len; i++) {
char c = [unescapedStr characterAtIndex:i];
NSString *replaceWithStr = nil;
if (c == '\"')
{
replaceWithStr = #""";
}
else if (c == '\'')
{
replaceWithStr = #"'";
}
else if (c == '<')
{
replaceWithStr = #"<";
}
else if (c == '>')
{
replaceWithStr = #">";
}
else if (c == '&')
{
replaceWithStr = #"&";
}
if (replaceWithStr == nil) {
// The current character is not an XML escape character, increase subrange length
subrange.length += 1;
} else {
// The current character will be replaced, but append any pending substring first
if (subrange.length > 0) {
NSString *substring = [unescapedStr substringWithRange:subrange];
[mStr appendString:substring];
}
[mStr appendString:replaceWithStr];
subrange.location = i + 1;
subrange.length = 0;
}
}
// Got to end of unescapedStr so append any pending substring, in the
// case of no escape characters this will append the whole string.
if (subrange.length > 0) {
if (subrange.location == 0) {
[mStr appendString:unescapedStr];
} else {
NSString *substring = [unescapedStr substringWithRange:subrange];
[mStr appendString:substring];
}
}
return [NSString stringWithString:mStr];
}
+ (NSString*) formatSimpleNode:(NSString*)tagname value:(NSString*)value
{
NSAssert(tagname != nil, #"tagname is nil");
NSAssert([tagname length] > 0, #"tagname is the empty string");
if (value == nil || [value length] == 0) {
// Certain XML parsers don't like empty nodes like "<foo/>", use "<foo />" instead
return [NSString stringWithFormat:#"<%# />", tagname];
} else {
NSString *escapedValue = [self xmlSimpleEscape:value];
return [NSString stringWithFormat:#"<%#>%#</%#>", tagname, escapedValue, tagname];
}
}
Here is my swift category for html encoding/decoding:
extension String
{
static let htmlEscapedDictionary = [
"&": "&",
""" : "\"",
"'" : "'",
"9" : "'",
"" : "'",
"" : "'",
">" : ">",
"<" : "<"]
var escapedHtmlString : String {
var newString = "\(self)"
for (key, value) in String.htmlEscapedDictionary {
newString.replace(value, withString: key)
}
return newString
}
var unescapedHtmlString : String {
let encodedData = self.dataUsingEncoding(NSUTF8StringEncoding)!
let attributedOptions : [String: AnyObject] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
]
let attributedString = NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil, error: nil)!
return attributedString.string
}
mutating func replace(originalString:String, withString newString:String)
{
let replacedString = self.stringByReplacingOccurrencesOfString(originalString, withString: newString, options: nil, range: nil)
self = replacedString
}
}
I guess a reverse of htmlEscapedDictionary could've been used as well in unescapedHtmlString
Note: As MarkBau pointed out in the comment below: Since Swift does not guarantee the order of dictionaries, make sure to replace & first.
I put together a quick example project using Mike and Tod's answers here.
Makes the encoding/unencoding dead simple:
NSString *html = #"<p>This \"paragraph\" contains quoted & 'single' quoted stuff.</p>";
NSLog(#"Original String: %#", html);
NSString *escapedHTML = [html xmlSimpleEscapeString];
NSLog(#"Escaped String: %#", escapedHTML);
NSString *unescapedHTML = [escapedHTML xmlSimpleUnescapeString];
NSLog(#"Unescaped String: %#", unescapedHTML);
This easiest solution is to create a category as below:
Here’s the category’s header file:
#import <Foundation/Foundation.h>
#interface NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding;
#end
And here’s the implementation:
#import "NSString+URLEncoding.h"
#implementation NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding));
}
#end
And now we can simply do this:
NSString *raw = #"hell & brimstone + earthly/delight";
NSString *url = [NSString stringWithFormat:#"http://example.com/example?param=%#",
[raw urlEncodeUsingEncoding:NSUTF8StringEncoding]];
NSLog(url);
The credits for this answer goes to the website below:-
http://madebymany.com/blog/url-encoding-an-nsstring-on-ios
Refer below answer:
NSString *content = global.strPrivacyPolicy;
content = [[[[[content stringByReplacingOccurrencesOfString: #"&" withString: #"&"]
stringByReplacingOccurrencesOfString:#""" withString:#"\" "]
stringByReplacingOccurrencesOfString: #"'" withString:#"'"]
stringByReplacingOccurrencesOfString: #">" withString: #">"]
stringByReplacingOccurrencesOfString: #"<" withString:#"<"];
[_webViewPrivacy loadHTMLString:content baseURL:nil];
Use the message in the example below :
anyStringConverted = [anyString stringByReplacingOccurrencesOfString:#"\n" withString:#"<br>"];
This converts 'new line' command to corresponding html code. But to convert symbols, you have to write the corresponding html number.
You can see the complete list of html numbers here at
http://www.ascii.cl/htmlcodes.htm
I found the only way that uses only built-in functions (not manual parsing) and covers all cases. Requires AppKit/UIKit in addition to Foundation. This is Swift but can easily be Objective-C:
func encodedForHTML() -> String {
// make a plain attributed string and then use its HTML write functionality
let attrStr = NSAttributedString(string: self)
// by default, the document outputs a whole HTML element
// warning: if default apple implementation changes, this may need to be tweaked
let options: [NSAttributedString.DocumentAttributeKey: Any] = [
.documentType: NSAttributedString.DocumentType.html,
.excludedElements: [
"html",
"head",
"meta",
"title",
"style",
"p",
"body",
"font",
"span"
]
]
// generate data and turn into string
let data = try! attrStr.data(from: NSRange(location: 0, length: attrStr.length), documentAttributes: options)
let str = String(data: data, encoding: .utf8)!
// remove <?xml line
return str.components(separatedBy: .newlines).dropFirst().first!
}