Skip to content

Instantly share code, notes, and snippets.

@kujirahand
Created October 9, 2024 15:08
Show Gist options
  • Save kujirahand/6d6abb811bacd83fa823f637db2a9262 to your computer and use it in GitHub Desktop.
Save kujirahand/6d6abb811bacd83fa823f637db2a9262 to your computer and use it in GitHub Desktop.
バイナリ郵便番号データを基にして住所を表示するプログラム
use std::io::Read;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
// 優美番号データファイルの宣言 --- (*1)
const FILE_CODE: &str = "zipcode.bin"; // 郵便番号情報のデータ
const KEN_TXT: &str = "ken.txt"; // 都道府県
const SHI_TXT: &str = "shi.txt"; // 市区町村
const CHO_TXT: &str = "cho.txt"; // 町域
fn main() {
// コマンドライン引数を得る --- (*2)
let args: Vec<String> = std::env::args().collect();
// 引数が1つでない場合はエラーを表示して終了
if args.len() != 2 {
eprintln!("[使い方] {} (郵便番号)", args[0]);
std::process::exit(1);
}
let zipcode = &args[1].replace("-", "");
let zipcode: u32 = zipcode.parse().unwrap_or_else(|_| {
eprintln!("[エラー] 郵便番号は7桁の数字で指定してください");
std::process::exit(1);
});
find_address(zipcode);
}
// 郵便番号を検索して都道府県、市区町村、町域を表示する --- (*3)
fn find_address(zipcode: u32) {
// 郵便番号ファイルを開く
let file = std::fs::File::open(FILE_CODE).unwrap();
// 64ビットずつファイルを読んで、対象となる郵便番号を探す --- (*4)
let mut reader = std::io::BufReader::new(file);
let mut buf = [0u8; 8];
let mut found = false;
while let Ok(b) = reader.read(&mut buf) {
if b == 0 { break; }
// バッファの中に郵便番号があるか調べる
let packed = u64::from_be_bytes(buf);
// 各フィールドをビットシフトして取り出す --- (*5)
let code = ((packed >> 40) & 0xFFFFFF) as u32; // 24ビット
let ken_id = ((packed >> 34) & 0x3F) as u8; // 6ビット
let shi_id = ((packed >> 23) & 0x7FF) as u16; // 11ビット
let cho_id = ((packed >> 6) & 0x1FFFF) as u32; // 17ビット
let _unused = (packed & 0x3F) as u8; // 6ビット
if zipcode == code {
// 郵便番号が見つかったので都道府県、市区町村、町域を表示
let s = show_address(ken_id, shi_id, cho_id);
println!("〒{} → {}", zipcode, s);
found = true;
}
}
if !found { eprintln!("[エラー] 郵便番号が見つかりません"); }
}
// 都道府県、市区町村、町域のIDから文字列を表示する --- (*6)
fn show_address(ken_id: u8, shi_id: u16, cho_id: u32) -> String {
// ファイル名を指定して指定した行の文字列を得る
let get_data = |filename: &str, target_id: u32| -> String {
// ファイルを開く --- (*7)
let path = Path::new(filename);
let file = File::open(&path).expect("ファイルを開けませんでした");
// 行をバッファで読み取る --- (*8)
let reader = io::BufReader::new(file);
for (index, line) in reader.lines().enumerate() {
let line = line.expect("行を読み取れませんでした");
if index as u32 == target_id { // 指定行ならその行を返す --- (*9)
return line;
}
}
String::from("---") // 指定したtarget_idが見つからなかった時
};
// 実際の文字列を得る
let ken = get_data(KEN_TXT, ken_id as u32);
let shi = get_data(SHI_TXT, shi_id as u32);
let cho = get_data(CHO_TXT, cho_id as u32);
format!("{} {} {}", ken, shi, cho)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment