为javascript输入转义NSString

Escape NSString for javascript input

本文关键字:NSString 转义 输入 javascript      更新时间:2023-09-26

我有一串ASCII字符(由[NSString stringWithFormat:@"%c", someNumber]随机创建),我想使用该字符串作为javascript方法的输入。比如:

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

如何转义NSString?我试图查看encodeURI和decodeURI,但还没有找到任何解决方案。

NSJSONSerialization就在角落里。将NSString转义为Javascript字符串字面值很难,而且很容易出错。(JSONKit使用代码行来处理它https://github.com/johnezang/JSONKit/blob/82157634ca0ca5b6a4a67a194dd11f15d9b72835/JSONKit.m#L1423)

下面是一个小的类别方法来转义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

还有一点需要注意,你必须在javascript函数的参数中使用双引号。例如,

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

经过无数个小时的研究,我想出了一个解决方案。原来我遇到了一个问题,我没有转义回车'r,所以这个函数解决了我的问题。

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

这是我发现的一个很好的网站,它引导我找到了这个解决方案。http://www.wilsonmar.com/1eschars.htm

通过ASCII,我假定您的意思是它是0x00到0x7F范围内的字节。在这个范围内,根据http://www.json.org,您唯一需要转义的字符是'"和控制字符:0x00-0x1F和0x7F。如果你在做简单的替换,控制字符会变得有点棘手,所以我会一个字符一个字符地转义字符串,可能是这样的(根本没有测试):

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

以下是ES5规范的相关部分:

除结束引号、反斜杠、回车、行分隔符、段落分隔符和换行符外,所有字符都可以在字符串字面上出现。任何字符都可以以转义序列的形式出现。

对于某些字符有反斜杠转义(您可以在后面几页找到),并且任何字符都可以用十六进制表示为'uXXXX

如果你需要一个解决方案,将工作与扩展ASCII符号(如拉丁符号)和/或unicode,你可以使用这个:

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

我不知道上面的代码点是如何用单字符表示的。这些字符似乎也无法在javascript中表示。

您是否尝试过类似的操作:

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

只需将转义函数放入string调用中就可以了。这取决于你为什么要转义

这是@zetachang上面的回答的后续。你必须在javascript函数的参数中使用双引号。例如,

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

我将使用NSJSONSerialization将字符串转换为JSON数组,然后将结果JSON字符串粘贴到JavaScript函数参数中。这样,我就不必担心JSON字符串是否包含在单引号或双引号中。

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