Лучший способ избежать символов, таких как новая строка и двойные кавычки, в NSString
Скажем, у меня есть NSString (или NSMutableString), содержащий:
I said "Hello, world!".
He said "My name's not World."
Как лучше всего это превратить:
I said \"Hello, world!\".\nHe said \"My name\'s not World.\"
Придется ли мне вручную использовать -replaceOccurrencesOfString:withString:
снова и снова, чтобы экранировать символы, или есть более простой способ? Эти строки могут содержать символы из других алфавитов / языков.
Как это делается на других языках с другими строковыми классами?
Ответов (7)7
Я не думаю, что существует какой-либо встроенный метод для «экранирования» определенного набора символов.
Если символы, которых вы хотите избежать, четко определены, я бы, вероятно, придерживался предложенного вами простого решения, грубо заменяя экземпляры символов.
Имейте в виду, что если в исходной строке уже есть экранированные символы, вы, вероятно, захотите избежать их «двойного экранирования». Один из способов добиться этого - пройти и «отключить экранирование» любых экранированных символьных строк в строке, прежде чем снова экранировать их все.
Если вам нужно поддерживать переменный набор экранированных символов, взгляните на методы NSScanner «scanUpToCharactersFromSet: intoString:» и «scanCharactersFromSet: intoString:». Вы можете использовать эти методы в NSScanner для перемещения по строке, копируя части из раздела «scanUpTo» в изменяемую строку без изменений и копируя части из определенного набора символов только после их экранирования.
Это фрагмент, который я использовал в прошлом, и он работает довольно хорошо:
- (NSString *)escapeString:(NSString *)aString
{
NSMutableString *returnString = [[NSMutableString alloc] init];
for(int i = 0; i < [aString length]; i++) {
unichar c = [aString characterAtIndex:i];
// if char needs to be escaped
if((('\\' == c) || ('\'' == c)) || ('"' == c)) {
[returnString appendFormat:@"\\%c", c];
} else {
[returnString appendFormat:@"%c", c];
}
}
return [returnString autorelease];
}
Возможно, вы даже захотите изучить использование библиотеки регулярных выражений (доступно множество вариантов, RegexKit - популярный выбор). Не должно быть слишком сложно найти заранее написанное регулярное выражение для escape-строк, которое обрабатывает особые случаи, такие как существующие экранированные символы.
Сделай это:
NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Ссылка: http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/
Я думаю, что в подобных случаях полезно работать с символом за раз, либо в байтах UniChars, либо в байтах UTF8. Если вы используете UTF-8, то vis(3)
большую часть работы он сделает за вас (см. Ниже). Могу я спросить, почему вы хотите избежать одинарных кавычек в строке с двойными кавычками? Как вы планируете обрабатывать многобайтовые символы? В приведенном ниже примере я использую UTF-8, кодируя 8-битные символы с помощью восьмеричных escape-символов C-Style. Это также можно отменить с помощью unvis(3)
.
#import <Foundation/Foundation.h>
#import <vis.h>
@interface NSString (Escaping)
- (NSString *)stringByEscapingMetacharacters;
@end
@implementation NSString (Escaping)
- (NSString *)stringByEscapingMetacharacters
{
const char *UTF8Input = [self UTF8String];
char *UTF8Output = [[NSMutableData dataWithLength:strlen(UTF8Input) * 4 + 1 /* Worst case */] mutableBytes];
char ch, *och = UTF8Output;
while ((ch = *UTF8Input++))
if (ch == '\'' || ch == '\'' || ch == '\\' || ch == '"')
{
*och++ = '\\';
*och++ = ch;
}
else if (isascii(ch))
och = vis(och, ch, VIS_NL | VIS_TAB | VIS_CSTYLE, *UTF8Input);
else
och+= sprintf(och, "\\%03hho", ch);
return [NSString stringWithUTF8String:UTF8Output];
}
@end
int
main(int argc, const char *argv[])
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSLog(@"%@", [@"I said \"Hello, world!\".\nHe said \"My name's not World.\"" stringByEscapingMetacharacters]);
[pool drain];
return 0;
}