LoginSignup
3
3

More than 5 years have passed since last update.

OBJC ブロックを使ってCSVファイルの読み込み

Last updated at Posted at 2014-05-03

Objective-Cでブロックを使ったカンマ区切り(似非CSV)の読み込みの例。
類似フォーマットのファイル読み込みは、ブロック化すると汎用性が高まるかも。ちなみにCSVの読み込みは、本当にカンマを区切るだけです。

Objective-Cで読む場合

ソースコード(github)

// CSVファイルを読み、1行毎にblockを呼び出す.
// blockの引数は、1行をカンマで分割した配列.
// 例: @"ab,cd,efg" なら@[@"ab,@"cd",@"efg"]を返す.
//
// @param comment 行頭にcommentがある場合は、その行を読み飛ばす. コメント不要の場合はnil.
+(BOOL)readCsv:(NSString*)filePath withCommentStr:(NSString*)comment block:(void (^)(NSArray*))block {
    // TestのためにmainBundleではなくbundleForClassを利用している。
    if( filePath == nil ) {
        return NO;
    }

    NSString* text = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    if( text == nil ) {
        return NO;
    }
    NSArray* lines = [text componentsSeparatedByString:@"\n"];

    for(NSString* line in lines) {
        // 行頭にコメント文字列を含む場合は、その行を読み飛ばす.
        if( line.length == 0 ||
           (comment != nil && [line hasPrefix:comment])) {
            continue;
        }

        NSArray* item = [line componentsSeparatedByString:@","];
        block(item);
    }
    return YES;
}

+(BOOL)readCsv:(NSString*)filePath block:(void (^)(NSArray*))block {
    return [TextFileHelper readCsv:filePath withCommentStr:nil block:block];
}


Test.csvの内容
Test.csv=<<EOF
12,34,56
abc,de,fgh,
#, abcdefg,agd
ABC,,ABC
"ABC,DEF"
END
EOF

// 利用例
- (void)testReadCSVWithNoComment
{
    NSString* filePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"Test" ofType:@"csv"];

    NSArray* expects = @[
                         @[@"12",@"34",@"56"],
                         @[@"abc",@"de",@"fgh", @""],
                         @[@"#",@" abcdefg",@"agd"],
                         @[@"ABC",@"",@"ABC"],
                         @[@"¥"ABC", @"DEF¥""],
                         @[@"",@"",@"",@"",@""],
                         @[@"END"]];

    __block int num = 0;

    [TextFileHelper readCsv:filePath block:^(NSArray* cols) {
        XCTAssertEqualObjects(expects[num], cols, @"index=%d", num);
        num++;
    }];

    XCTAssertEqual(num, expects.count, @"%d != %d", num, expects.count);
}

ちなみにRubyでファイルからカンマ区切りを読むと...

※下記ソース,動作は未確認...

# gemを不使用の例.
def readCsv(filename, &block)
  File.open(filename) do |file|
    file.each_line do |line|
      # 行頭が#ならコメントとして読みとばす
      next if line =~ /^#/
      cols = line.split(/¥s*,¥s*/)
      block.call(cols) if block
    end
   end
end

それぞれの言語に良いところはあるけど、文字列処理はrubyの方が楽かな、と。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3