开发者

Escape NSString for javascript input

I have a string of ASCII characters (created randomly by [NSString stringWithFormat:@"%c", someNumber]), and I want to use that string as input for a javascript method. Something like:

[webView_ stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"my_javascript_method开发者_运维技巧(\"%@\")", myASCIIString]];

How can I escape the NSString? I tried to look into encodeURI and decodeURI, but haven't found any solution yet.


NSJSONSerialization is right there in the corner. To escape NSString to Javascript string literal is hard and could be done wrong easily. (JSONKit use lines of code to deal with it https://github.com/johnezang/JSONKit/blob/82157634ca0ca5b6a4a67a194dd11f15d9b72835/JSONKit.m#L1423)

Below is a little category method to escape the NSString object.

#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

Also, one thing to notice, you've gotta use double quotes in the argument to the javascript function. E.g.,

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

[self.webView stringByEvaluatingJavaScriptFromString:javascriptCall];


After countless hours of researching a solution here is what i came up with. Its turns out i was running into an issue where i wasn't escaping the carriage return \r so this function solved my problems.

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

Here is a great website i found that lead me to this solution. http://www.wilsonmar.com/1eschars.htm


By ASCII, I presume you mean it's a byte in the range 0x00 to 0x7F. In this range, according to http://www.json.org the only characters you need to escape are \, ", and the control characters: 0x00-0x1F and 0x7F. The control characters get a bit tricky if you're doing simple substitutions, so I'd go through character by character to escape the string, maybe something like this (not tested at all):

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


Here's the relevant part of the ES5 specification:

All characters may appear literally in a string literal except for the closing quote character, backslash, carriage return, line separator, paragraph separator, and line feed. Any character may appear in the form of an escape sequence.

There are backslash escapes for some characters (which you can find a couple of pages down), and any character can be represented in hex as \uXXXX. They're explained (with examples) a couple of pages down in the spec.


If you need a solution which will work with extended ASCII symbols (eg Latin symbols) and/or unicode, you can use this:

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

I don't know how this behaves with code points above that representable by a unichar. It seems like such characters cannot be represented in javascript either.


Have you tried anything similar to:

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

Just dropping the escape function into the string call may work for you. It really depends WHY you want this escaped


This is a follow on to @zetachang's answer above. You've gotta use double quotes in the argument to the javascript function. E.g.,

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


I'd use NSJSONSerialization to convert the string into a JSON array and then paste the resulting JSON String into the JavaScript function parameter. This way I don't have to worry about whether the JSON string is contained within a single quote or double quote.

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜