Objective C HTML escape/unescape

Ale*_*yne 74 html iphone cocoa-touch escaping objective-c

想知道是否有一种简单的方法在Objective C中进行简单的HTML转义/ unescape.我想要的是这样的伪代码:

NSString *string = @"<span>Foo</span>";
[string stringByUnescapingHTML];
Run Code Online (Sandbox Code Playgroud)

哪个回报

<span>Foo</span>
Run Code Online (Sandbox Code Playgroud)

希望能够解决所有其他HTML实体,甚至是像Ӓ之类的ASCII代码.

Cocoa Touch/UIKit中有没有方法可以做到这一点?

Mic*_*all 90

查看我的NSString类别的XMLEntities.有解码XML实体(包括所有HTML字符引用),编码XML实体,剥离标记以及从字符串中删除换行符和空格的方法:

- (NSString *)stringByStrippingTags;
- (NSString *)stringByDecodingXMLEntities; // Including all HTML character references
- (NSString *)stringByEncodingXMLEntities;
- (NSString *)stringWithNewLinesAsBRs;
- (NSString *)stringByRemovingNewLinesAndWhitespace;
Run Code Online (Sandbox Code Playgroud)

  • 什么是时髦的许可证?不能用于日记和期刊? (9认同)
  • 似乎它不支持西里尔语.你见过一个支持吗? (2认同)

Nik*_*bak 35

来自Google Toolbox for Mac的另一个HTML NSString类别
尽管有这个名字,但这也适用于iOS.

http://google-toolbox-for-mac.googlecode.com/svn/trunk/Foundation/GTMNSString+HTML.h

/// Get a string where internal characters that are escaped for HTML are unescaped 
//
///  For example, '&amp;' becomes '&'
///  Handles &#32; and &#x32; cases as well
///
//  Returns:
//    Autoreleased NSString
//
- (NSString *)gtm_stringByUnescapingFromHTML;
Run Code Online (Sandbox Code Playgroud)

我不得不在项目中只包含三个文件:标题,实现和GTMDefines.h.

  • 值得注意的是,如果你正在寻找与此相反的东西,那就是`'&'`变成`'&amp;'`,这也包含在` - (NSString*)gtm_stringByEscapingForHTML;`中,稍后在文件中定义. (2认同)

And*_*ant 30

链接包含以下解决方案.Cocoa CF具有CFXMLCreateStringByUnescapingEntities功能,但在iPhone上不可用.

@interface MREntitiesConverter : NSObject <NSXMLParserDelegate>{
    NSMutableString* resultString;
}

@property (nonatomic, retain) NSMutableString* resultString;

- (NSString*)convertEntitiesInString:(NSString*)s;

@end


@implementation MREntitiesConverter

@synthesize resultString;

- (id)init
{
    if([super init]) {
        resultString = [[NSMutableString alloc] init];
    }
    return self;
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s {
        [self.resultString appendString:s];
}

- (NSString*)convertEntitiesInString:(NSString*)s {
    if (!s) {
        NSLog(@"ERROR : Parameter string is nil");
    }
    NSString* xmlStr = [NSString stringWithFormat:@"<d>%@</d>", s];
    NSData *data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    NSXMLParser* xmlParse = [[[NSXMLParser alloc] initWithData:data] autorelease];
    [xmlParse setDelegate:self];
    [xmlParse parse];
    return [NSString stringWithFormat:@"%@",resultString];
}

- (void)dealloc {
    [resultString release];
    [super dealloc];
}

@end
Run Code Online (Sandbox Code Playgroud)

  • xmlParse也泄漏btw,只需添加一个autorelease到它和returnStr (6认同)
  • 尽管iOS上没有"CFXMLCreateStringByUnescapingEntities",但您可以从CFXMLParser.c(来自Core Foundation源代码)复制其定义并在项目中使用它.我测试了它,它的工作原理. (4认同)
  • 我发现这段代码删除了所有的html标签(例如它只是从"<a href="xxx"> Facebook </a>"中留下了"Facebook"),有时候复杂的html传入时什么都不返回.所以,不幸的是不符合我的目标. (2认同)

And*_*lik 29

这是我所做的令人难以置信的黑客攻击解决方案,但是如果你想简单地转义字符串而不用担心解析,请执行以下操作:

-(NSString *)htmlEntityDecode:(NSString *)string
    {
        string = [string stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""];
        string = [string stringByReplacingOccurrencesOfString:@"&apos;" withString:@"'"];
        string = [string stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"];
        string = [string stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"];
        string = [string stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"]; // Do this last so that, e.g. @"&amp;lt;" goes to @"&lt;" not @"<"

        return string;
    }
Run Code Online (Sandbox Code Playgroud)

我知道这绝不是优雅的,但它完成了工作.然后,您可以通过调用解码元素:

string = [self htmlEntityDecode:string];
Run Code Online (Sandbox Code Playgroud)

就像我说的,这是hacky,但它的工作原理.如果要编码字符串,只需反转stringByReplacingOccurencesOfString参数即可.

  • 根据使用频率以及通过提高效率实际节省多少时间,在此进行微量优化可能没有意义.由于我们在这里处理HTML,很可能在某处有网络请求,并且返回的时间要比上面显示的代码要长几千倍才能执行.我可能倾向于不优化此代码. (6认同)
  • 性能怎么样?你要经历5次字符串.它看起来效率不高;) (5认同)

orj*_*orj 11

在iOS 7中,您可以使用NSAttributedString导入HTML以将HTML实体转换为NSString的功能.

例如:

@interface NSAttributedString (HTML)
+ (instancetype)attributedStringWithHTMLString:(NSString *)htmlString;
@end

@implementation NSAttributedString (HTML)
+ (instancetype)attributedStringWithHTMLString:(NSString *)htmlString
{
    NSDictionary *options = @{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                               NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding) };

    NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding];

    return [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
}

@end
Run Code Online (Sandbox Code Playgroud)

然后在您想要清理实体的代码中:

NSString *cleanString = [[NSAttributedString attributedStringWithHTMLString:question.title] string];
Run Code Online (Sandbox Code Playgroud)

这可能是最简单的方法,但我不知道它的性能如何.您应该非常确定您的"清理"内容不包含任何<img>标签或类似内容,因为此方法会在HTML期间将这些图像下载到NSAttributedString转换.:)

  • 只是抬头,NSAttributedString在构造函数中做了很多事情,就像旋转runloop一样.我没能在主线程上使用它而不会让UIKit非常不高兴. (2认同)

Bad*_*ate 5

这是一个中和所有字符的解决方案(通过将它们全部用于unicode值的HTML编码实体)...根据我的需要使用它(确保来自用户但放在webview中的字符串不能有任何字符串XSS攻击):

接口:

@interface NSString (escape)
- (NSString*)stringByEncodingHTMLEntities;
@end
Run Code Online (Sandbox Code Playgroud)

执行:

@implementation NSString (escape)

- (NSString*)stringByEncodingHTMLEntities {
    // Rather then mapping each individual entity and checking if it needs to be replaced, we simply replace every character with the hex entity

    NSMutableString *resultString = [NSMutableString string];
    for(int pos = 0; pos<[self length]; pos++)
        [resultString appendFormat:@"&#x%x;",[self characterAtIndex:pos]];
    return [NSString stringWithString:resultString];
}

@end
Run Code Online (Sandbox Code Playgroud)

用法示例:

UIWebView *webView = [[UIWebView alloc] init];
NSString *userInput = @"<script>alert('This is an XSS ATTACK!');</script>";
NSString *safeInput = [userInput stringByEncodingHTMLEntities];
[webView loadHTMLString:safeInput baseURL:nil];
Run Code Online (Sandbox Code Playgroud)

你的里程会有所不同.