Created
October 9, 2024 15:08
-
-
Save kujirahand/6d6abb811bacd83fa823f637db2a9262 to your computer and use it in GitHub Desktop.
バイナリ郵便番号データを基にして住所を表示するプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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