web-dev-qa-db-ja.com

NSDataバイトをNSStringに変換しますか?

BEncoding ObjC class を使用して.torrentファイルをデコードしようとしています。

NSData *rawdata = [NSData dataWithContentsOfFile:@"/path/to/the.torrent"];
NSData *torrent = [BEncoding objectFromEncodedData:rawdata];

NSLogtorrentを取得すると、次の結果が得られます。

{
    announce = <68747470 3a2f2f74 6f727265 6e742e75 62756e74 752e636f 6d3a3639 36392f61 6e6e6f75 6e6365>;
    comment = <5562756e 74752043 44207265 6c656173 65732e75 62756e74 752e636f 6d>;
    "creation date" = 1225365524;
    info =     {
        length = 732766208;
        name = <7562756e 74752d38 2e31302d 6465736b 746f702d 69333836 2e69736f>;
        "piece length" = 524288;
....

nameをNSStringに変換するにはどうすればよいですか?私が試してみました..

NSData *info = [torrent valueForKey:@"info"];
NSData *name = [info valueForKey:@"name"];
unsigned char aBuffer[[name length]];
[name getBytes:aBuffer length:[name length]];
NSLog(@"File name: %s", aBuffer);

..これはデータを取得しますが、その後に追加のユニコードのゴミがあるようです:

File name: ubuntu-8.10-desktop-i386.iso)

私も試しました( ここから )..

NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)];

..しかし、これはランダムな文字の束を返すようです:

扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳

最初の方法(Appleドキュメンテーション)に記載されているように)は、いくつかの追加のバイトを使用して、ほとんどのデータを正しく返します。 ObjCについての知識の過失が原因である可能性が高い。

49
dbr
_NSData *torrent = [BEncoding objectFromEncodedData:rawdata];
_

NSLogトレントを取得すると、次の結果が得られます。

_{
    ⋮
}
_

NSDataではなく、NSDictionaryになります。

_unsigned char aBuffer[[name length]];
[name getBytes:aBuffer length:[name length]];
NSLog(@"File name: %s", aBuffer);
_

..これはデータを取得しますが、その後に追加のユニコードのゴミがあるようです:

_File name: ubuntu-8.10-desktop-i386.iso)
_

いいえ、ファイル名は問題なく取得されました。間違って印刷しただけです。 _%s_はヌル文字で終了するC文字列を受け取ります。データオブジェクトのバイトはnullで終了しません(これらは単なるバイトであり、必ずしもエンコーディングの文字ではなく、0(文字としてnull)は完全に有効なバイトです)。もう1文字を割り当て、配列の最後の文字を0に設定する必要があります。

_size_t length = [name length] + 1;
unsigned char aBuffer[length];
[name getBytes:aBuffer length:length];
aBuffer[length - 1] = 0;
NSLog(@"File name: %s", aBuffer);
_

ただし、NSDataオブジェクト内のデータのヌル終了は間違っています(本当にdoC文字列が必要な場合を除く)。すぐに正しい方法に行きます。

私も試しました[…] ..

_NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)];
_

..しかし、これはランダムな漢字を返すようです:

_扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳
_

これは、バイトが(通常)1バイトで1文字をエンコードするUTF-8であるためです。

unicharはUTF-16であり、_stringWithCharacters:length:_は受け入れます。そのエンコーディングでは、1文字は(通常)2バイトです。 (したがって、sizeof(unichar)による除算:バイト数を2で除算して文字数を取得します。)

「ここにUTF-16データがあります」と言って、2バイトごとに文字を作成しました。バイトの各ペアは1文字ではなく2文字であると想定されていたため、ガベージを受け取りました(ほとんどがCJK表意文字であることが判明しました)。


あなたは自分の質問に答えました UTF-8でエンコードされた文字列の_stringWithUTF8String:_は_stringWithCString:encoding:_よりも単純であることを除いて、かなりよくできています。

ただし、長さがある場合(NSDataがある場合と同じように)、_initWithBytes:length:encoding:_を使用する方が簡単で、より適切です。ヌル終了データを必要としないため、簡単です。既に持っている長さを使用するだけです。 (リリースまたは自動リリースすることを忘れないでください。)

19
Peter Hosey

それは、私が思うに再強調されるべき重要なポイントです。それは判明しました、

NSString *content = [NSString stringWithUTF8String:[responseData bytes]];

とは異なり、

NSString *content = [[NSString alloc]  initWithBytes:[responseData bytes]
              length:[responseData length] encoding: NSUTF8StringEncoding];

最初はNULLで終了するバイト文字列を期待しますが、2番目はそうではありません。上記の2つの場合、バイト文字列が正しく終了していない場合、最初の例でcontentはNULLになります。

99
Alasdair Allan

どう?

NSString *content = [[[NSString alloc] initWithData:myData
                                           encoding:NSUTF8StringEncoding] autorelease];
20
user102008

素晴らしく素早いアプローチは、NSStringstringWithFormat初期化子を使用して手助けすることです。あまり使用されない文字列フォーマットの機能の1つは、文字列を出力するときに最大文字列長を指定する機能です。この便利な機能を使用すると、NSDataを非常に簡単に文字列に変換できます。

NSData *myData = [self getDataFromSomewhere];
NSString *string = [NSString stringWithFormat:@"%.*s", [myData length], [myData bytes]];

ログに出力する場合は、さらに簡単にすることができます。

NSLog(@"my Data: %.*s", [myData length], [myData bytes]);
7
Ethan

ああ、NSStringメソッドstringWithCStringは正しく動作します:

とともに bencoding.h/.mファイルがプロジェクトに追加され、完全な.mファイル:

#import <Foundation/Foundation.h>
#import "BEncoding.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Read raw file, and de-bencode
    NSData *rawdata = [NSData dataWithContentsOfFile:@"/path/to/a.torrent"];
    NSData *torrent = [BEncoding objectFromEncodedData:rawdata];

    // Get the file name
    NSData *infoData = [torrent valueForKey:@"info"];
    NSData *nameData = [infoData valueForKey:@"name"];
    NSString *filename = [NSString stringWithCString:[nameData bytes] encoding:NSUTF8StringEncoding];
    NSLog(@"%@", filename);

    [pool drain];
    return 0;
}

..そして出力:

ubuntu-8.10-desktop-i386.iso
6
dbr

ネットワークからの読み取りなど、文字列に変換されるデータを制御できない場合は、NSString -initWithBytes:length:encoding:これにより、定義済みの結果を取得するためにNULLで終了する文字列を持つことに依存しなくなりました。 Appleのドキュメントには、cStringがNULLで終了する文字列でない場合、結果は未定義であると書かれていることに注意してください。

2
Jay O'Conor

NSDataでカテゴリを使用します。

NSData + NSString.h

_@interface NSData (NSString)

- (NSString *)toString;

@end
_

NSData + NSString.m

_#import "NSData+NSString.h"

@implementation NSData (NSString)

- (NSString *)toString
{
    Byte *dataPointer = (Byte *)[self bytes];
    NSMutableString *result = [NSMutableString stringWithCapacity:0];
    NSUInteger index;
    for (index = 0; index < [self length]; index++)
    {
        [result appendFormat:@"0x%02x,", dataPointer[index]];
    }
    return result;
}

@end
_

それからちょうどNSLog(@"Data is %@", [nsData toString])"

2

これを試すことができます。元気です。

DLog(@"responeData: %@", [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease]);
2
user2652623

これは動作します。

NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
0
MobilePundits

NSDataからBase64エンコード文字列を作成する必要がある場合があります。たとえば、電子メールMIMEを作成するとき。この場合、次を使用します。

#import "NSData+Base64.h"
NSString *string = [data base64EncodedString];
0
wzbozon