2016-11-27 9 views
0

私はTVHクライアントのATVバージョンを使用しています - これを見ていなければ、顔の狂気をちらっと見てみる価値があります。これには、電子プログラムガイドを含むデータを返すJSON APIがあります。チャネルによっては、アクセント付きの文字がデータに挿入されることがあります。ここに例がありますが、これはPostmanの結果です。説明のchar:JSONデータにNSJSONSerializationが終了する原因となる「不良」文字が含まれています

{ 
     "eventId": 14277, 
     "episodeId": 14278, 
     "channelName": "49.3 CometTV", 
     "channelUuid": "02fe96403d58d53d71fde60649bf2b9a", 
     "channelNumber": "49.3", 
     "start": 1480266000, 
     "stop": 1480273200, 
     "title": "The Brain That Wouldn't Die", 
     "description": "Dr. Bill Cortner and his fianc�e, Jan Compton , are driving to his lab when they get into a horrible car accident. Compton is decapitated. But Cortner is not fazed by this seemingly insurmountable hurdle. His expertise is in transplants, and he is excited to perform the first head transplant. Keeping Compton's head alive in his lab, Cortner plans the groundbreaking yet unorthodox surgery. First, however, he needs a body." 
    }, 

このデータはNSJSONSerializationに供給される場合は、エラーを返します。だから、これを回避するために、データが最初にこの機能に供給された:コントロールデータ内の文字はなく、上記の場合と同様にアクセントがある場合に

+ (NSDictionary*)convertFromJsonToObjectFixUtf8:(NSData*)responseData error:(__autoreleasing NSError**)error { 
    NSMutableData *FileData = [NSMutableData dataWithLength:[responseData length]]; 
    for (int i = 0; i < [responseData length]; ++i) { 
     char *a = &((char*)[responseData bytes])[i]; 
     if ((int)*a >0 && (int)*a < 0x20) { 
      ((char*)[FileData mutableBytes])[i] = 0x20; 
     } else { 
      ((char*)[FileData mutableBytes])[i] = ((char*)[responseData bytes])[i]; 
     } 
    } 
    NSDictionary* json = [NSJSONSerialization JSONObjectWithData:FileData //1 
                 options:kNilOptions 
                  error:error]; 
    if(*error) { 
     NSLog(@"[JSON Error (2nd)] output - %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]); 
     NSDictionary *userInfo = @{ NSLocalizedDescriptionKey:[NSString stringWithFormat:NSLocalizedString(@"Tvheadend returned malformed JSON - check your Tvheadend's Character Set for each mux and choose the correct one!", nil)] }; 
     *error = [[NSError alloc] initWithDomain:@"Not ready" code:NSURLErrorBadServerResponse userInfo:userInfo]; 
     return nil; 
    } 
    return json; 
} 

これはケースをクリーンアップします。そのデータをフィードすると、「Tvheadendが不正な形式のJSONを返しました」というエラーが表示されます。

1つの問題は、ユーザーが限られた数の選択肢の中から文字セットを変更でき、サーバーがクライアントにその内容を知らせないことです。したがって、1つのチャネルでUTF8と別のISO-8891-1を使用する可能性があり、クライアント側でどちらを使用するかを知る方法がありません。

だから誰もこのデータを処理する方法を提案して、きれいな文字列をNSJSONSerializationに入力することはできますか?

+0

*クライアント側で使用する方法を知る方法がありません。* ['Content-Type'](https://www.w3.org/Protocols/rfc1341/4_Content-Type.html)をチェックしましたか? ? 'charset'パラメータが設定されている場合、クライアントはそれを使用します。 –

+0

ヘッダーには "ext/x-json; charset = UTF-8"と表示されていますが、これは既定値であり、各チャネルは独自のエンコーディングを持つことができます。実際には、デフォルトを変更しても常にUTF8と言います。 –

+0

それを聞いて申し訳ありません。 [ICU](http://site.icu-project.org/)にはエンコーディング[自動検出](http://userguide.icu-project.org/conversion/detection)機能があります。 iOS用のICUのポートがありますが、自動検出だけでそのすべてを引き出すことは厄介です。 –

答えて

1

私が見ている問題の根本的な原因はまだ分かりません。サーバは上記のような高ビット文字だけでなく、制御文字も含んでいることがわかりました。他のスレッドを見てみると、私はこの問題を見ている唯一の人ではないので、うまくいけば他の人がこの便利なものを見つけるでしょう...

基本的なやりかたは、元のデータをサーバからUTF8を使って文字列に変換することです。これらの「不良」文字がある場合、変換は失敗します。したがって、結果の文字列が空であるかどうかを確認し、別の文字セットを試してみてください。最終的にデータが戻ってきます。これで、その文字列を取り除き、任意の制御文字を取り除きます。これでUTF8が「クリーン」になった結果をUTF8 NSDataに変換します。それはエラーなくJSON変換を通過します。ピー!ここで

は私が最終的に使用する溶液である:

// ... the original data from the URL is in responseData 
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; 
if (str == nil) { 
    str = [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding]; 
} 
if (str == nil) { 
    str = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding]; 
} 
NSCharacterSet *controls = [NSCharacterSet controlCharacterSet]; 
NSString *stripped = [[str componentsSeparatedByCharactersInSet:controls] componentsJoinedByString:@""]; 
NSData *data = [stripped dataUsingEncoding:NSUTF8StringEncoding]; 
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; 

私は誰かが、これは重宝しますね!

+0

これは実行されますが、ユニコード文字は私のためにガベージASCII文字として終わります...おそらく、私はSwiftへの私の翻訳で何か間違っています。 – aehlke

関連する問題