Encode NSString for XML/HTML

后端 未结 14 1211
误落风尘
误落风尘 2020-11-28 04:25

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

相关标签:
14条回答
  • 2020-11-28 04:40

    Swift 4

    extension String {
        var xmlEscaped: String {
            return replacingOccurrences(of: "&", with: "&")
                .replacingOccurrences(of: "\"", with: """)
                .replacingOccurrences(of: "'", with: "'")
                .replacingOccurrences(of: ">", with: ">")
                .replacingOccurrences(of: "<", with: "&lt;")
        }
    }
    
    0 讨论(0)
  • 2020-11-28 04:44

    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:@"&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;
    }
    
    0 讨论(0)
  • 2020-11-28 04:45

    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:@"&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 *)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 = [
                ("&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.

    0 讨论(0)
  • 2020-11-28 04:45

    Here is my swift category for html encoding/decoding:

    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

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

    0 讨论(0)
  • 2020-11-28 04:47

    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);
    
    0 讨论(0)
  • 2020-11-28 04:49

    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 = @"&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];    
      }
    }
    
    0 讨论(0)
提交回复
热议问题