概要
- 例:データにカンマや改行(LFやCR)が含まれているとき、ダブルクォーテーションで囲うことでそれらを取り扱えるようにした場合…のCSVファイルの読み込みをしたい。
- 単純に
,
で区切りたいところですが、要素に"ぶっかけ,混ぜ混ぜ派"
のように,
が含まれている可能性があるので、正規表現を使って分割します。 - 今回の要件にあう正規表現は以下の通り
\"([^\"]*)\"
サンプルデータの作成
なんちゃって個人情報を利用してサンプルデータを作成。
"ぶっかけ,混ぜ混ぜ派"
のように、各行最後の要素に,
を入れてテスト。
dummy.csv
"森下 優","もりした ゆう","morishita_yuu@example.com","女","73","1945/8/6","既婚","福島県","080- 141-4402","au","ぶっかけ,混ぜ混ぜ派"
"関口 啓介","せきぐち けいすけ","sekiguchi_keisuke@example.com","男","26","1993/1/24","既婚","東京都","090-3212-8148","au","ぶっかけ,せき止め派"
"谷村 雄太","たにむら ゆうた","tanimura_yuuta@example.com","男","51","1967/8/23","既婚","愛知県","080-6212-5174","ドコモ","手前ルー,混ぜ混ぜ派"
コード
呼び出し側
NSArray *usersInfo = [self loadCsvFileWithDoubleQuotes:[NSURL fileURLWithPath:@"/Users/dummy.csv"]];
// 結果確認
for (NSArray *userInfo in usersInfo) {
NSLog(@"%@", [NSString stringWithCString:[userInfo.description cStringUsingEncoding:NSASCIIStringEncoding] encoding:NSNonLossyASCIIStringEncoding]);
}
関数
/**
@brief 各要素がダブルコーテーションで囲まれたCSVファイルの内容を取得する
@param csvURL 対象CSVのパス
@return カンマで分けられた要素配列(ダブルコーテーションを除く)
@warning Encoding=UTF8
読み込み失敗時は空配列を返す
*/
- (NSArray *)loadCsvFileWithDoubleQuotes:(NSURL *)csvURL {
NSError *loadError = nil;
// CSVファイルの読み込み
NSString *csvContents = [[NSString alloc] initWithContentsOfURL:csvURL
encoding:NSUTF8StringEncoding
error:&loadError];
if (loadError) {
NSLog(@"%@", [loadError localizedDescription]);
return @[];
}
// 正規表現を使ってカンマ区切りで各要素に分解し読み込み
NSMutableArray *extractWholeResult = [NSMutableArray array]; // 全体の抽出結果
NSRegularExpression *reg = [[NSRegularExpression alloc] initWithPattern:@"\"([^\"]*)\"" options:0 error:nil]; // ダブルコーテーションに囲まれた部分を抽出する
[csvContents enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOL * _Nonnull stop) {
NSArray *matches = [reg matchesInString:line options:0 range:NSMakeRange(0, [line length])];
NSMutableArray *extractResult = [[NSMutableArray alloc] init]; // 行ごとの抽出結果
for (NSTextCheckingResult *result in matches) {
for (int i = 1; i < [result numberOfRanges]; i++) {
NSRange r = [result rangeAtIndex:i];
[extractResult addObject:[line substringWithRange:r]];
}
}
[extractWholeResult addObject: extractResult];
}];
return extractWholeResult;
}
ログ出力
2019-02-05 10:12:58.803886+0900 ExtractWithRegularExpression[86252:3480833] (
"森下 優",
"もりした ゆう",
"morishita_yuu@example.com",
"女",
73,
"1945/8/6",
"既婚",
"福島県",
"080- 141-4402",
au,
"ぶっかけ,混ぜ混ぜ派"
)
2019-02-05 10:12:58.803940+0900 ExtractWithRegularExpression[86252:3480833] (
"関口 啓介",
"せきぐち けいすけ",
"sekiguchi_keisuke@example.com",
"男",
26,
"1993/1/24",
"既婚",
"東京都",
"090-3212-8148",
au,
"ぶっかけ,せき止め派"
)
2019-02-05 10:12:58.803968+0900 ExtractWithRegularExpression[86252:3480833] (
"谷村 雄太",
"たにむら ゆうた",
"tanimura_yuuta@example.com",
"男",
51,
"1967/8/23",
"既婚",
"愛知県",
"080-6212-5174",
"ドコモ",
"手前ルー,混ぜ混ぜ派"
)
ライフハックなやり方(邪道ですね)
","
で componentsSeparatedByString
をして、冒頭と末尾のダブルコーテーションを取ってやる。