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