우선, 나는 이것을 발견했습니다. Objective C HTML escape / unescape 이지만 작동하지 않습니다.
내 인코딩 된 문자 (RSS 피드, btw에서 가져옴)는 다음과 같습니다. &
인터넷 전체를 검색하고 관련 토론을 찾았지만 특정 인코딩에 대한 수정 사항이 없어서 16 진수 문자라고 생각합니다.
답변
이를 문자 엔티티 참조 라고 합니다. 형식을 취할 때 숫자 엔티티 참조&#<number>;
라고 합니다. 기본적으로 대체되어야하는 바이트의 문자열 표현입니다. 의 경우 ISO-8859-1 문자 인코딩 체계에서 값이 38 인 문자를 나타냅니다 .&
&
앰퍼샌드가 RSS로 인코딩되어야하는 이유는 예약 된 특수 문자이기 때문입니다.
해야 할 일은 문자열을 파싱하고 엔티티를과 사이의 값 &#
과 일치하는 바이트로 바꾸는 것 ;
입니다. 객관적인 C에서이 작업을 수행하는 좋은 방법은 없지만 이 스택 오버플로 질문 이 도움이 될 수 있습니다.
편집 : 약 2 년 전에 이에 대한 답변 이후 몇 가지 훌륭한 솔루션이 있습니다. 아래 @Michael Waterfall의 답변을 참조하십시오.
답변
HTML에 대한 내 NSString 카테고리를 확인하십시오 . 사용 가능한 방법은 다음과 같습니다.
- (NSString *)stringByConvertingHTMLToPlainText;
- (NSString *)stringByDecodingHTMLEntities;
- (NSString *)stringByEncodingHTMLEntities;
- (NSString *)stringWithNewLinesAsBRs;
- (NSString *)stringByRemovingNewLinesAndWhitespace;
답변
Daniel의 작품은 기본적으로 매우 훌륭하며 몇 가지 문제를 해결했습니다.
-
NSSCanner의 건너 뛰는 문자를 제거했습니다 (그렇지 않으면 두 개의 연속 엔티티 사이의 공백이 무시됩니다.
[스캐너 setCharactersToBeSkipped : nil];
-
분리 된 ‘&’기호가있을 때 구문 분석을 수정했습니다 (이에 대한 ‘올바른’출력이 무엇인지 모르겠습니다. 방금 파이어 폭스와 비교했습니다).
예 :
&#ABC DF & B' & C' Items (288)
다음은 수정 된 코드입니다.
- (NSString *)stringByDecodingXMLEntities {
NSUInteger myLength = [self length];
NSUInteger ampIndex = [self rangeOfString:@"&" options:NSLiteralSearch].location;
// Short-circuit if there are no ampersands.
if (ampIndex == NSNotFound) {
return self;
}
// Make result string with some extra capacity.
NSMutableString *result = [NSMutableString stringWithCapacity:(myLength * 1.25)];
// First iteration doesn't need to scan to & since we did that already, but for code simplicity's sake we'll do it again with the scanner.
NSScanner *scanner = [NSScanner scannerWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSCharacterSet *boundaryCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@" \t\n\r;"];
do {
// Scan up to the next entity or the end of the string.
NSString *nonEntityString;
if ([scanner scanUpToString:@"&" intoString:&nonEntityString]) {
[result appendString:nonEntityString];
}
if ([scanner isAtEnd]) {
goto finish;
}
// Scan either a HTML or numeric character entity reference.
if ([scanner scanString:@"&" intoString:NULL])
[result appendString:@"&"];
else if ([scanner scanString:@"'" intoString:NULL])
[result appendString:@"'"];
else if ([scanner scanString:@""" intoString:NULL])
[result appendString:@"\""];
else if ([scanner scanString:@"<" intoString:NULL])
[result appendString:@"<"];
else if ([scanner scanString:@">" intoString:NULL])
[result appendString:@">"];
else if ([scanner scanString:@"&#" intoString:NULL]) {
BOOL gotNumber;
unsigned charCode;
NSString *xForHex = @"";
// Is it hex or decimal?
if ([scanner scanString:@"x" intoString:&xForHex]) {
gotNumber = [scanner scanHexInt:&charCode];
}
else {
gotNumber = [scanner scanInt:(int*)&charCode];
}
if (gotNumber) {
[result appendFormat:@"%C", (unichar)charCode];
[scanner scanString:@";" intoString:NULL];
}
else {
NSString *unknownEntity = @"";
[scanner scanUpToCharactersFromSet:boundaryCharacterSet intoString:&unknownEntity];
[result appendFormat:@"&#%@%@", xForHex, unknownEntity];
//[scanner scanUpToString:@";" intoString:&unknownEntity];
//[result appendFormat:@"&#%@%@;", xForHex, unknownEntity];
NSLog(@"Expected numeric character entity but got &#%@%@;", xForHex, unknownEntity);
}
}
else {
NSString *amp;
[scanner scanString:@"&" intoString:&]; //an isolated & symbol
[result appendString:amp];
/*
NSString *unknownEntity = @"";
[scanner scanUpToString:@";" intoString:&unknownEntity];
NSString *semicolon = @"";
[scanner scanString:@";" intoString:&semicolon];
[result appendFormat:@"%@%@", unknownEntity, semicolon];
NSLog(@"Unsupported XML character entity %@%@", unknownEntity, semicolon);
*/
}
}
while (![scanner isAtEnd]);
finish:
return result;
}
답변
iOS 7부터는 NSAttributedString
with NSHTMLTextDocumentType
속성 을 사용하여 기본적으로 HTML 문자를 디코딩 할 수 있습니다 .
NSString *htmlString = @" & & < > ™ © ♥ ♣ ♠ ♦";
NSData *stringData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType};
NSAttributedString *decodedString;
decodedString = [[NSAttributedString alloc] initWithData:stringData
options:options
documentAttributes:NULL
error:NULL];
디코딩 된 속성 문자열은 이제 & & <> ™ © ♥ ♣ ♠ ♦로 표시됩니다.
참고 : 이것은 메인 스레드에서 호출 된 경우에만 작동합니다.
답변
아무도 가장 간단한 옵션 중 하나 인 Mac 용 Google 도구 상자 를 언급하지 않는 것 같습니다
(이름에도 불구하고 iOS에서도 작동합니다.)
https://github.com/google/google-toolbox-for-mac/blob/master/Foundation/GTMNSString%2BHTML.h
/// Get a string where internal characters that are escaped for HTML are unescaped
//
/// For example, '&' becomes '&'
/// Handles   and 2 cases as well
///
// Returns:
// Autoreleased NSString
//
- (NSString *)gtm_stringByUnescapingFromHTML;
그리고 프로젝트에 헤더, 구현 및 GTMDefines.h
.
답변
나는 이것을 GitHub 또는 다른 것에 게시해야한다. 이것은 NSString의 범주에 속 NSScanner
하고 구현에 사용 되며 일반적인 기호 엔티티뿐만 아니라 16 진수 및 10 진수 문자 엔티티를 모두 처리합니다.
또한 이 코드를 사용하는 내 출시 된 앱 에서 중요한 것으로 판명 된 잘못된 형식의 문자열 (& 뒤에 잘못된 문자 시퀀스가 오는 경우)을 비교적 우아하게 처리 합니다.
- (NSString *)stringByDecodingXMLEntities {
NSUInteger myLength = [self length];
NSUInteger ampIndex = [self rangeOfString:@"&" options:NSLiteralSearch].location;
// Short-circuit if there are no ampersands.
if (ampIndex == NSNotFound) {
return self;
}
// Make result string with some extra capacity.
NSMutableString *result = [NSMutableString stringWithCapacity:(myLength * 1.25)];
// First iteration doesn't need to scan to & since we did that already, but for code simplicity's sake we'll do it again with the scanner.
NSScanner *scanner = [NSScanner scannerWithString:self];
do {
// Scan up to the next entity or the end of the string.
NSString *nonEntityString;
if ([scanner scanUpToString:@"&" intoString:&nonEntityString]) {
[result appendString:nonEntityString];
}
if ([scanner isAtEnd]) {
goto finish;
}
// Scan either a HTML or numeric character entity reference.
if ([scanner scanString:@"&" intoString:NULL])
[result appendString:@"&"];
else if ([scanner scanString:@"'" intoString:NULL])
[result appendString:@"'"];
else if ([scanner scanString:@""" intoString:NULL])
[result appendString:@"\""];
else if ([scanner scanString:@"<" intoString:NULL])
[result appendString:@"<"];
else if ([scanner scanString:@">" intoString:NULL])
[result appendString:@">"];
else if ([scanner scanString:@"&#" intoString:NULL]) {
BOOL gotNumber;
unsigned charCode;
NSString *xForHex = @"";
// Is it hex or decimal?
if ([scanner scanString:@"x" intoString:&xForHex]) {
gotNumber = [scanner scanHexInt:&charCode];
}
else {
gotNumber = [scanner scanInt:(int*)&charCode];
}
if (gotNumber) {
[result appendFormat:@"%C", charCode];
}
else {
NSString *unknownEntity = @"";
[scanner scanUpToString:@";" intoString:&unknownEntity];
[result appendFormat:@"&#%@%@;", xForHex, unknownEntity];
NSLog(@"Expected numeric character entity but got &#%@%@;", xForHex, unknownEntity);
}
[scanner scanString:@";" intoString:NULL];
}
else {
NSString *unknownEntity = @"";
[scanner scanUpToString:@";" intoString:&unknownEntity];
NSString *semicolon = @"";
[scanner scanString:@";" intoString:&semicolon];
[result appendFormat:@"%@%@", unknownEntity, semicolon];
NSLog(@"Unsupported XML character entity %@%@", unknownEntity, semicolon);
}
}
while (![scanner isAtEnd]);
finish:
return result;
}
답변
이것은 RegexKitLite 프레임 워크를 사용하여 수행하는 방법입니다 .
-(NSString*) decodeHtmlUnicodeCharacters: (NSString*) html {
NSString* result = [html copy];
NSArray* matches = [result arrayOfCaptureComponentsMatchedByRegex: @"\\&#([\\d]+);"];
if (![matches count])
return result;
for (int i=0; i<[matches count]; i++) {
NSArray* array = [matches objectAtIndex: i];
NSString* charCode = [array objectAtIndex: 1];
int code = [charCode intValue];
NSString* character = [NSString stringWithFormat:@"%C", code];
result = [result stringByReplacingOccurrencesOfString: [array objectAtIndex: 0]
withString: character];
}
return result;
}
이것이 누군가를 도울 수 있기를 바랍니다.
