2011-04-06 12 views
5

Tengo una cadena de caracteres ASCII (creada aleatoriamente por [NSString stringWithFormat: @ "% c", someNumber]), y quiero usar esa cadena como entrada para un método javascript. Algo como:Escape NSString para javascript input

[webView_ stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"my_javascript_method(\"%@\")", myASCIIString]]; 

¿Cómo puedo escapar del NSString? Intenté investigar en encodeURI y decodeURI, pero aún no he encontrado ninguna solución.

+0

Para el registro: 'stringByEvaluatingJavaScriptFromString' es Unicode correcto; no tiene que escapar de caracteres que no sean ASCII. –

Respuesta

5

Por ASCII, supongo que quiere decir que es un byte en el rango de 0x00 a 0x7F. En este rango, según http://www.json.org, los únicos caracteres que necesita para escapar son \, ", y los caracteres de control: 0x00-0x1F y 0x7F. Los caracteres de control se ponen un poco difícil si usted está haciendo sustituciones simples, por lo que me gustaría ir a través carácter por carácter para escapar de la cadena, tal vez algo como esto (no probado en absoluto):

const char *chars = [myASCIIString UTF8String]; 
NSMutableString *escapedString = [NSMutableString string]; 
while (*chars) 
{ 
    if (*chars == '\\') 
     [escapedString appendString:@"\\\\"]; 
    else if (*chars == '"') 
     [escapedString appendString:@"\\\""]; 
    else if (*chars < 0x1F || *chars == 0x7F) 
     [escapedString appendFormat:@"\\u%04X", (int)*chars]; 
    else 
     [escapedString appendFormat:@"%c", *chars]; 
    ++chars; 
} 
NSString *js = [NSString stringWithFormat:@"my_js_function(\"%@\")", escapedString]; 
+0

Esta solución funciona, pero tiene dos errores. Primero, esto no escapará a las comillas dobles correctamente. Debería leer '" \\\ "" 'en lugar de' "\" "'. En segundo lugar, agregará la cadena escapada a la cadena original, en lugar de crear una nueva. La segunda línea debería leer algo como 'NSMutableString * escapedString = [NSMutableString stringWithString: @" "];'. –

+0

@Eric: tienes razón. He arreglado la respuesta. ¡Gracias! –

+0

No es necesario escapar de ASCII. Al menos desde iOS 5, UIWebView toma bien los literales que no son ASCII. Y no lo estás haciendo bien de todos modos; se romperá con caracteres Unicode genuinos de rango superior. –

0

Ha intentado algo similar a:

[webView_ stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"my_javascript_method(escape(\"%@\"))", myASCIIString]]; 

Apenas cayendo la función de escape en la llamada cadena puede funcionar para usted. Realmente depende por qué quieres este escapó

+0

Lo probé y no funcionó, no se llamó al método. La razón por la que deseo que se escape es porque mi cadena ASCII contiene algunos caracteres ilegibles (ya que se creó a partir de ASCII de números aleatorios de 0 a 255) y rompe la entrada. –

+0

Eso no funcionará en absoluto – AlBeebe

1

Here's the relevant part of the ES5 specification:

Todos los personajes pueden aparecer literalmente en una cadena literal excepto por el carácter de comillas de cierre, la barra invertida, retorno de carro, separador de línea, separador de párrafos, y salto de línea . Cualquier personaje puede aparecer en la forma de una secuencia de escape.

Hay barra invertida se escapa para algunos caracteres (que se puede encontrar un par de páginas abajo), y cualquier carácter puede ser representado en hexadecimal como \uXXXX. Se les explica (con ejemplos) un par de páginas abajo en la especificación.

9

Después de incontables horas de investigar una solución aquí es lo que se me ocurrió. Resulta que me encontré con un problema en el que no estaba escapando del retorno del carro, así que esta función resolvió mis problemas.

-(NSString *)addBackslashes:(NSString *)string { 
    /* 

    Escape characters so we can pass a string via stringByEvaluatingJavaScriptFromString 

    */ 

    // Escape the characters 
    string = [string stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; 
    string = [string stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 
    string = [string stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; 
    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; 
    string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; 
    string = [string stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; 
    return string; 
} 

Aquí hay un excelente sitio web que encontré que me llevan a esta solución. http://www.wilsonmar.com/1eschars.htm

+1

esto solucionó mis problemas, gracias :) –

+0

¡Solucionado mi problema! –

12

NSJSONSerialization está allí en la esquina. Para escapar NSString a Javascript cadena literal es difícil y podría hacerse mal fácilmente. (JSONKit use líneas de código para manejarlo https://github.com/johnezang/JSONKit/blob/82157634ca0ca5b6a4a67a194dd11f15d9b72835/JSONKit.m#L1423)

A continuación se muestra un pequeño método de categoría para escapar del objeto NSString.

#import "NSString+JavascriptEscape.h" 

@implementation NSString (JavascriptEscape) 

- (NSString *)stringEscapedForJavasacript { 
    // valid JSON object need to be an array or dictionary 
    NSArray* arrayForEncoding = @[self]; 
    NSString* jsonString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:arrayForEncoding options:0 error:nil] encoding:NSUTF8StringEncoding]; 

    NSString* escapedString = [jsonString substringWithRange:NSMakeRange(2, jsonString.length - 4)]; 
    return escapedString; 
} 

@end 

También, una cosa para notar, tienes que usar comillas dobles en el argumento de la función javascript. Por ejemplo,

NSString *javascriptCall = 
    [NSString stringWithFormat:@"MyJavascriptFunction(\"%@\")", escapedString]; 

[self.webView stringByEvaluatingJavaScriptFromString:javascriptCall]; 
+0

¡Funcionó como un encanto! Lo único que se puede mencionar es que esto escapa de las comillas dobles, por lo que debe usar comillas dobles en la llamada stringByEvaluatingJavaScriptFromString. He puesto un ejemplo en una respuesta a continuación. –

+0

Gracias, @ChrisPrince, ¡simplemente añada su sugerencia a la respuesta! – zetachang

0

Si necesita una solución que funcionará con símbolos extendidos ASCII (por ejemplo, signos Latina) y/o Unicode, puede utilizar esto:

- (NSString*) escapeStringForJavascript:(NSString*)input 
{ 
    NSMutableString* ret = [NSMutableString string]; 
    int i; 
    for (i = 0; i < input.length; i++) 
    { 
     unichar c = [input characterAtIndex:i]; 
     if (c == '\\') 
     { 
      // escape backslash 
      [ret appendFormat:@"\\\\"]; 
     } 
     else if (c == '"') 
     { 
      // escape double quotes 
      [ret appendFormat:@"\\\""]; 
     } 
     else if (c >= 0x20 && c <= 0x7E) 
     { 
      // if it is a printable ASCII character (other than \ and "), append directly 
      [ret appendFormat:@"%c", c]; 
     } 
     else 
     { 
      // if it is not printable standard ASCII, append as a unicode escape sequence 
      [ret appendFormat:@"\\u%04X", c]; 
     } 
    } 
    return ret; 
} 

No sé cómo este se comporta con puntos de código por encima de ese representable por unichar.Parece que tales caracteres no pueden ser representados en javascript tampoco.

0

Este es un seguimiento de la respuesta de @ zetachang anterior. Tienes que usar comillas dobles en el argumento de la función javascript. Por ejemplo,

NSString *javascriptCall = 
    [NSString stringWithFormat:@"MyJavascriptFunction(\"%@\")", escapedString]; 
[self.webView stringByEvaluatingJavaScriptFromString:javascriptCall]; 
0

que haría uso de NSJSONSerialization para convertir la cadena en una matriz JSON y luego pegar el JSON cadena resultante en el parámetro de la función JavaScript. De esta forma, no tengo que preocuparme si la cadena JSON está contenida dentro de una comilla simple o una comilla doble.

NSString* inputString = ... // your raw string to escape 
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:@[inputString] options:0 error:nil]; 
NSString* jsString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 
NSString* jsScript = [NSString stringWithFormat:@"yourFunction(%@[0])",jsString]; 
// then pass jsScript to a JavaScript interpreter 
Cuestiones relacionadas