【C言語】
sscanf関数を使用したCSV形式の郵便番号解析方法

■この記事の概要

この記事は、C言語のsscanf関数を用いて、CSV形式の郵便番号データから情報を解析する方法を解説します。

コード例を通して住所や名前などのデータを抽出する方法を学べ、郵便番号から住所を検索する応用例も含まれています。


■基礎編:sscanfの正規表現でcsvを解析する方法

#include <stdio.h>
#include <stdlib.h>
//構造体の宣言
typedef struct 個人情報 {
    char    住所[1024];
    char    氏名[1024];
    int     年齢;
}   個人情報 ;
//構造体配列の定義
static  個人情報  一覧[10];

//構造体ポインタを使った構造体のメンバ表示
static  void 個人情報表示(個人情報 *p)
{
    printf("■%s\n",p->住所);
    printf("%s\n",p->氏名);
    printf("%d\n",p->年齢);
}
static void 全個人情報表示(void)
{
    for(個人情報 *p = &一覧[0]; p->氏名[0] != '\0' ;p++){
        個人情報表示(p);
    }
}
static void 全個人情報設定(FILE *fp)
{
    個人情報 *p = &一覧[0];
    char    buf[BUFSIZ];
    const int max = sizeof(一覧)/sizeof(一覧[0]);
    while(fgets(buf,BUFSIZ,fp) != NULL){
        //空行はスキップ
        if(buf[0] == '\n'){
            continue;
        }
        //入力データが多すぎないか確認
        int id = p - &一覧[0];
        if(id >= max){
            fprintf(stderr,"最大値 %d 件を超えました\n",max);
            exit(1);
        }
        //【住所,氏名,年齢】3フィールド読み込む
        int ret = sscanf(buf,
            "%[^,],%[^,],%d",//正規表現【カンマ以外,カンマ以外,数字】
            p->住所,
            p->氏名,
            &(p->年齢)
        );
        if(ret != 3){//3フィールド読めなかったら無視
            fprintf(stderr,"入力異常 ret=%d:%s",ret,buf);
            continue ;
        }
        p++ ;
    }
}
int     main(void)
{
    char    *input = "input.csv";
    FILE    *fp = fopen(input,"r");
    if(fp == NULL){
        fprintf(stderr,"%s 開かん\n",input);
        exit(1);
    }
    
    全個人情報設定(fp);
    全個人情報表示();

    fclose(fp);
}

コピペしてコンパイル&実行して動作を確認してください。

●input.csvの例

愛知,山田太郎,4
岐阜,佐藤次郎,5
三重,鈴木三郎,6

応用編:郵便番号データベースから住所を求める

//
//  郵便番号から住所を表示するプログラム
//	2024/06/10	UTF版		
//		作者:柴ONE
//					
//https://www.post.japanpost.jp/zipcode/dl/utf-zip.html
//住所の郵便番号(1レコード1行、UTF-8形式)(CSV形式)
//最新データのダウンロード(zip形式)
//住所の郵便番号最新全データのダウンロードができます。
//最新データのダウンロード(zip形式:2.09Mバイト)
#if 0
https://www.post.japanpost.jp/zipcode/dl/utf-readme.html
郵便番号データファイルの形式等
この郵便番号データファイルでは、以下の順に配列しています。
1全国地方公共団体コード(JIS X0401、X0402)……… 半角数字
2(旧)郵便番号(5桁)……………………………………… 半角数字
■3郵便番号(7桁)……………………………………… 半角数字
4都道府県名 ………… 全角カタカナ(コード順に掲載) (※1)
5市区町村名 ………… 全角カタカナ(コード順に掲載) (※1)
6町域名 ……………… 全角カタカナ(五十音順に掲載) (※1)
■7都道府県名 ………… 漢字(コード順に掲載) (※1,2)
■8市区町村名 ………… 漢字(コード順に掲載) (※1,2)
■9町域名 ……………… 漢字(五十音順に掲載) (※1,2)
10一町域が二以上の郵便番号で表される場合の表示 (※3) (「1」は該当、「0」は該当せず)
11小字毎に番地が起番されている町域の表示 (※4) (「1」は該当、「0」は該当せず)
12丁目を有する町域の場合の表示 (「1」は該当、「0」は該当せず)
13一つの郵便番号で二以上の町域を表す場合の表示 (※5) (「1」は該当、「0」は該当せず)
14更新の表示(※6)(「0」は変更なし、「1」は変更あり、「2」廃止(廃止データのみ使用))
15変更理由 (「0」は変更なし、「1」市政・区政・町政・分区・政令指定都市施行、「2」住居表示の実施、「3」区画整理、「4」郵便区調整等、「5」訂正、「6」廃止(廃止データのみ使用))
#endif
#include 	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	<stdbool.h>
void 郵便番号から住所表示(FILE *fp,char *郵便番号)
{
	bool	検出 = false ;
	char 	buf[BUFSIZ];
	while (fgets(buf, BUFSIZ, fp) != NULL) {
		char csv[10][128];	//csv[0]は捨てる
		int ret = sscanf(buf,
            "%[^,],"		//csv[1]	,以外の単語,
			"%[^,],"		//csv[2]
			"\"%[0-9]\","	//csv[3]	"数字列",
			"%[^,],"		//csv[4]
			"%[^,],"		//csv[5]
			"%[^,],"		//csv[6]
			"\"%[^,\"]\","	//csv[7]	",と\"以外の単語",	
			"\"%[^,\"]\","	//csv[8]
			"\"%[^,\"]\"",	//csv[9]
			&csv[1][0],
			&csv[2][0],
			&csv[3][0],	//郵便番号(7桁)
			&csv[4][0],
			&csv[5][0],
			&csv[6][0],
			&csv[7][0],	//都道府県名
			&csv[8][0],	//市区町村名
			&csv[9][0]	//町域名
        );
		if(ret != 9){
			fprintf(stderr,"形式異常 %s\n",buf);
			continue;
		}
		if (strcmp(&csv[3][0], 郵便番号) != 0){
			continue;		
		}
		printf("%s➡住所:%s%s%s\n", 
			郵便番号,
			&csv[7][0], 
			&csv[8][0], 
			&csv[9][0]
		);
		検出 = true;
		break;
	}
	if(!検出){
		fprintf(stderr,"郵便番号 %s は見つかりませんでした\n",郵便番号);
	}
}
void	郵便番号入力(char *postnum)
{
	printf("郵便番号をハイフンなしで入れてね: ");
	int 	ret = scanf("%s",postnum);
	if(ret != 1){
		fprintf(stderr,"郵便番号異常\n");
		exit(1);
	}
	if(strlen(postnum) != 7){
		fprintf(stderr,"郵便番号異常 %zu桁 != 7桁(%s)\n",
			strlen(postnum),
			postnum);
		exit(1);
	}
}
FILE *郵便番号データファイル(void)
{
	const 	char *csvfilename = "utf_ken_all/utf_ken_all.csv";
	FILE 	*fp = fopen(csvfilename, "r");
	if (fp == NULL){
		fprintf(stderr,"%s 開かん\n",csvfilename);
		exit(1);
	}
	return 	fp;
}
int	main(void)	
{
	FILE *fp = 郵便番号データファイル();

	char 		郵便番号[128];
	郵便番号入力(郵便番号);

	郵便番号から住所表示(fp,郵便番号);

	fclose(fp);
}

コピペしてコンパイル&実行してみて下さい。


参考:

郵便番号データダウンロード