Pregunta

¿Hay alguna forma de codificar HTML una cadena (NSString) en Objective-C, algo similar a Server.HtmlEncode en .NET?

¿Fue útil?

Solución

No hay un método NSString que haga eso. Tendrá que escribir su propia función que haga reemplazos de cadenas. Es suficiente hacer los siguientes reemplazos:

  • '& amp;' = > " & amp; amp; "
  • '"' = > " & amp; quot; "
  • '\' '= > " & amp; # 39; "
  • '>' = > " & amp; gt; "
  • '<' = > " & amp; lt; "

Algo como esto debería hacer (no lo he intentado):

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

Otros consejos

Tomé el trabajo de Mike y lo convertí en una categoría para NSMutableString y NSString

Cree una categoría para NSMutableString con:

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

Cree una categoría para NSString con:

- (NSString *)xmlSimpleUnescapeString
{
    NSMutableString *unescapeStr = [NSMutableString stringWithString:self];

    return [unescapeStr xmlSimpleUnescape];
}


- (NSString *)xmlSimpleEscapeString
{
    NSMutableString *escapeStr = [NSMutableString stringWithString:self];

    return [escapeStr xmlSimpleEscape];
}

* Una versión Swift 2.0 *

La versión Objective-C es un poco más eficiente ya que realiza operaciones mutables en la cadena. Sin embargo, esta es una forma rápida de hacer un escape simple:

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

Podría haber utilizado las capacidades de puente de NSString para escribir algo muy similar a la versión de NSString, pero decidí hacerlo más rápido.

Uso Google Toolbox para Mac (funciona en iPhone). En particular, vea las adiciones a NSString en GTMNSString + HTML.h y GTMNSString + XML.h .

Para codificación de URL :

NSString * encodedString = [originalString
      stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

Consulte Documentación NSString de Apple para obtener más información.

Para codificación HTML :

Consulte CFXMLCreateStringByEscapingEntities , que forma parte de la biblioteca de Core Foundation XML , pero aún debería hacer el truco.

la rutina de samets olvidó el dígito hexadecimal. Aquí está la rutina que se me ocurrió que funciona:

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

Aquí hay una implementación más eficiente de esta lógica de escape 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];    
  }
}

Si puede usar NSXMLNode (en OS X) Aquí está el truco:

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

Aquí está mi categoría rápida para la codificación / decodificación html:

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

Supongo que un reverso de htmlEscapedDictionary podría haberse usado también en unescapedHtmlString

Nota: Como MarkBau señaló en el comentario a continuación: Dado que Swift no garantiza el orden de los diccionarios, asegúrese de reemplazar & primero.

No estoy completamente seguro de si funcionará en todos los casos, pero puede ser más fácil rodear su texto con CDATA:

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

qué es CDATA: ¿Qué significa <! [CDATA []] > en XML significa?

Arme un proyecto de ejemplo rápido usando las respuestas de Mike y Tod aquí .

Hace que la codificación / descodificación sea muy 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);

Swift 4

extension String {
    var xmlEscaped: String {
        return replacingOccurrences(of: "&", with: "&amp;")
            .replacingOccurrences(of: "\"", with: "&quot;")
            .replacingOccurrences(of: "'", with: "&#39;")
            .replacingOccurrences(of: ">", with: "&gt;")
            .replacingOccurrences(of: "<", with: "&lt;")
    }
}

Esta solución más fácil es crear una categoría de la siguiente manera:

Aquí & # 8217; s la categoría & # 8217; archivo de encabezado:

#import <Foundation/Foundation.h>
@interface NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding;
@end

Y aquí & # 8217; s la implementación:

#import "NSString+URLEncoding.h"
@implementation NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
               (CFStringRef)self,
               NULL,
               (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
               CFStringConvertNSStringEncodingToEncoding(encoding));
}
@end

Y ahora podemos simplemente hacer esto:

NSString *raw = @"hell & brimstone + earthly/delight";
NSString *url = [NSString stringWithFormat:@"http://example.com/example?param=%@",
            [raw urlEncodeUsingEncoding:NSUTF8StringEncoding]];
NSLog(url);

Los créditos para esta respuesta van al siguiente sitio web: -

http://madebymany.com/blog/url-encoding-an-nsstring-on-ios

Consulte la respuesta a continuación:

NSString *content = global.strPrivacyPolicy;
content =  [[[[[content stringByReplacingOccurrencesOfString: @"&amp;" withString: @"&"]
stringByReplacingOccurrencesOfString:@"&quot;"  withString:@"\" "]
stringByReplacingOccurrencesOfString: @"&#39;"  withString:@"'"]
stringByReplacingOccurrencesOfString: @"&gt;" withString: @">"]
stringByReplacingOccurrencesOfString:  @"&lt;" withString:@"<"];
[_webViewPrivacy loadHTMLString:content baseURL:nil];

Use el mensaje en el siguiente ejemplo:

anyStringConverted = [anyString stringByReplacingOccurrencesOfString:@"\n" withString:@"<br>"]; 

Esto convierte el comando 'nueva línea' en el código html correspondiente. Pero para convertir símbolos, debe escribir el número html correspondiente. Puede ver la lista completa de números html aquí en

http://www.ascii.cl/htmlcodes.htm

Encontré la única forma que usa solo funciones integradas (no el análisis manual) y cubre todos los casos. Requiere AppKit / UIKit además de Foundation. Esto es rápido pero puede ser fácilmente 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!
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top