ios 为 XML/HTML 编码 NSString

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/803676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:51:27  来源:igfitidea点击:

Encode NSString for XML/HTML

iosobjective-cencoding

提问by Billy

Is there a way to HTML encode a string (NSString) in Objective-C, something along the lines of Server.HtmlEncode in .NET?

有没有办法在 Objective-C 中对字符串 (NSString) 进行 HTML 编码,类似于 .NET 中的 Server.HtmlEncode?

回答by thesamet

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:

没有 NSString 方法可以做到这一点。您必须编写自己的函数来进行字符串替换。进行以下替换就足够了:

  • '&' => "&"
  • '"' => """
  • '\'' => "'"
  • '>' => ">"
  • '<' => "&lt;"
  • '&' => "&"
  • '"' => """
  • '\'' => "'"
  • '>' => ">"
  • '<' => "<"

Something like this should do (haven't tried):

应该这样做(还没有尝试过):

[[[[[myStr stringByReplacingOccurrencesOfString: @"&" withString: @"&amp;"]
 stringByReplacingOccurrencesOfString: @"\"" withString: @"&quot;"]
 stringByReplacingOccurrencesOfString: @"'" withString: @"&#39;"]
 stringByReplacingOccurrencesOfString: @">" withString: @"&gt;"]
 stringByReplacingOccurrencesOfString: @"<" withString: @"&lt;"];

回答by Tod Cunningham

I took Mike's work and turn it into a category for NSMutableString and NSString

我拿了 Mike 的作品,把它变成了 NSMutableString 和 NSString 的一个类别

Make a Category for NSMutableString with:

使用以下命令为 NSMutableString 创建一个类别:

- (NSMutableString *)xmlSimpleUnescape
{
    [self replaceOccurrencesOfString:@"&amp;"  withString:@"&"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&quot;" withString:@"\"" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&#x27;" withString:@"'"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&#39;"  withString:@"'"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&#x92;" withString:@"'"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&#x96;" withString:@"-"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&gt;"   withString:@">"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"&lt;"   withString:@"<"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];

    return self;
}

- (NSMutableString *)xmlSimpleEscape
{
    [self replaceOccurrencesOfString:@"&"  withString:@"&amp;"  options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"\"" withString:@"&quot;" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"'"  withString:@"&#x27;" options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@">"  withString:@"&gt;"   options:NSLiteralSearch range:NSMakeRange(0, [self length])];
    [self replaceOccurrencesOfString:@"<"  withString:@"&lt;"   options:NSLiteralSearch range:NSMakeRange(0, [self length])];

    return self;
}

Make a Category for NSString with:

使用以下命令为 NSString 创建一个类别:

- (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 *

* Swift 2.0 版本 *

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:

Objective-C 版本的效率更高一些,因为它对字符串执行可变操作。但是,这是进行简单转义的快速方法:

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 = [
            ("&amp;",  "&"),
            ("&quot;", "\""),
            ("&#x27;", "'"),
            ("&#39;",  "'"),
            ("&#x92;", "'"),
            ("&#x96;", "-"),
            ("&gt;",   ">"),
            ("&lt;",   "<")]

        return self.simpleReplace(mapList)
    }

    func xmlSimpleEscape() -> String
    {
        let mapList : SimpleToFromRepalceList = [
            ("&",  "&amp;"),
            ("\"", "&quot;"),
            ("'",  "&#x27;"),
            (">",  "&gt;"),
            ("<",  "&lt;")]

        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.

我本可以使用 NSString 桥接功能来编写与 NSString 版本非常相似的东西,但我决定做得更迅速。

回答by Chris Lundie

I use Google Toolbox for Mac(works on iPhone). In particular, see the additions to NSString in GTMNSString+HTML.hand GTMNSString+XML.h.

我使用Google Toolbox for Mac(适用于 iPhone)。特别是,请参阅GTMNSString+HTML.hGTMNSString+XML.h 中对 NSString 的添加

回答by e.James

For URL encoding:

对于 URL 编码

NSString * encodedString = [originalString
      stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

See Apple's NSString documentationfor more info.

有关更多信息,请参阅Apple 的 NSString 文档

For HTML encoding:

对于 HTML 编码

Check out CFXMLCreateStringByEscapingEntities, which is part of the Core Foundation XML library, but should still do the trick.

查看CFXMLCreateStringByEscapingEntities,它是 Core Foundation XML 库的一部分,但仍然可以解决问题。

回答by Mike

the samets's routine forgot the hex digit. Here's the routine I came up with that works:

samets 的例程忘记了十六进制数字。这是我想出的工作例程:

- (NSString*)convertEntities:(NSString*)string
{

NSString    *returnStr = nil;

    if( string )
    {
        returnStr = [ string stringByReplacingOccurrencesOfString:@"&amp;" withString: @"&"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&#x27;" withString:@"'"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&#x39;" withString:@"'"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&#x92;" withString:@"'"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&#x96;" withString:@"'"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"  ];

        returnStr = [ returnStr stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"  ];

        returnStr = [ [ NSString alloc ] initWithString:returnStr ];
    }

    return returnStr;
}

回答by dmitrynikolaev

If you can use NSXMLNode (on OS X) Here is the trick:

如果你可以使用 NSXMLNode(在 OS X 上)这里是诀窍:

NSString *string = @"test<me>"
NSXMLNode *textNode = [NSXMLNode textWithStringValue:string];
NSString *escapedString = [textNode.XMLString];

回答by MoDJ

Here is a more efficient implementation of this xml escape logic.

这是此 xml 转义逻辑的更有效实现。

+ (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 = @"&quot;";
    }
    else if (c == '\'')
    {
      replaceWithStr = @"&#x27;";
    }
    else if (c == '<')
    {
      replaceWithStr = @"&lt;";
    }
    else if (c == '>')
    {
      replaceWithStr = @"&gt;";
    }
    else if (c == '&')
    {
      replaceWithStr = @"&amp;";
    }

    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];    
  }
}

回答by livingtech

I put together a quick example project using Mike and Tod's answers here.

在这里使用 Mike 和 Tod 的答案整理了一个快速示例项目。

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);

回答by Sunkas

Here is my swift category for html encoding/decoding:

这是我用于 html 编码/解码的 swift 类别:

extension String
{
    static let htmlEscapedDictionary = [
        "&amp;": "&",
        "&quot;" : "\"",
        "&#x27;" : "'",
        "&#x39;" : "'",
        "&#x92;" : "'",
        "&#x96;" : "'",
        "&gt;" : ">",
        "&lt;" : "<"]

    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

我想在 unescapedHtmlString 中也可以使用反向的 htmlEscapedDictionary

Note:As MarkBau pointed out in the comment below: Since Swift does not guarantee the order of dictionaries, make sure to replace &first.

注意:正如 MarkBau 在下面的评论中指出的那样:由于 Swift 不保证字典的顺序,请确保先替换&

回答by nickeyzzz

I am not copletely sure if it will work in all cases, but may be it's easier to surround your text with CDATA:

我不确定它是否适用于所有情况,但用 CDATA 包围文本可能更容易:

<xmltag><![CDATA[some <b>long</b> <i>xml</i> text]]></xmltag>

what is CDATA: What does <![CDATA[]]> in XML mean?

什么是 CDATA: XML 中的 <![CDATA[]]> 是什么意思?