dataforge/generators/
address.rs

1//! 地址生成器模块
2
3use rand::seq::SliceRandom;
4use rand::Rng;
5use once_cell::sync::Lazy;
6use std::fs;
7
8/// 中国省份
9const PROVINCES: &[&str] = &[
10    "北京市", "天津市", "河北省", "山西省", "内蒙古自治区",
11    "辽宁省", "吉林省", "黑龙江省", "上海市", "江苏省",
12    "浙江省", "安徽省", "福建省", "江西省", "山东省",
13    "河南省", "湖北省", "湖南省", "广东省", "广西壮族自治区",
14    "海南省", "重庆市", "四川省", "贵州省", "云南省",
15    "西藏自治区", "陕西省", "甘肃省", "青海省", "宁夏回族自治区",
16    "新疆维吾尔自治区"
17];
18
19/// 城市后缀
20const CITY_SUFFIXES: &[&str] = &["市", "县", "区"];
21
22/// 街道后缀
23const STREET_SUFFIXES: &[&str] = &["街", "路", "大道", "巷", "胡同", "里"];
24
25/// 从文件加载街道前缀
26static STREET_PREFIXES: Lazy<Vec<String>> = Lazy::new(|| {
27    load_data_from_file("data/generators/address/street_prefixes.txt")
28});
29
30/// 从文件加载美国州名
31static US_STATES: Lazy<Vec<String>> = Lazy::new(|| {
32    load_data_from_file("data/generators/address/us_states.txt")
33});
34
35/// 从文件加载美国城市
36static US_CITIES: Lazy<Vec<String>> = Lazy::new(|| {
37    load_data_from_file("data/generators/address/us_cities.txt")
38});
39
40/// 从文件加载数据的辅助函数
41fn load_data_from_file(file_path: &str) -> Vec<String> {
42    match fs::read_to_string(file_path) {
43        Ok(content) => content
44            .lines()
45            .map(|line| line.trim().to_string())
46            .filter(|line| !line.is_empty())
47            .collect(),
48        Err(_) => {
49            // 如果文件不存在,返回默认数据
50            match file_path {
51                "data/generators/address/street_prefixes.txt" => vec![
52                    "长安".to_string(), "中山".to_string(), "人民".to_string(), 
53                    "解放".to_string(), "建设".to_string(), "和平".to_string()
54                ],
55                "data/generators/address/us_states.txt" => vec![
56                    "California".to_string(), "Texas".to_string(), "Florida".to_string(),
57                    "New York".to_string(), "Illinois".to_string(), "Pennsylvania".to_string()
58                ],
59                "data/generators/address/us_cities.txt" => vec![
60                    "New York".to_string(), "Los Angeles".to_string(), "Chicago".to_string(),
61                    "Houston".to_string(), "Phoenix".to_string(), "Philadelphia".to_string()
62                ],
63                _ => vec!["Default".to_string()]
64            }
65        }
66    }
67}
68
69/// 生成中国省份
70pub fn zh_province() -> String {
71    let mut rng = rand::thread_rng();
72    PROVINCES.choose(&mut rng).unwrap().to_string()
73}
74
75/// 生成中国城市
76pub fn zh_city() -> String {
77    let mut rng = rand::thread_rng();
78    let prefix_len = rng.gen_range(2..=4);
79    let mut city = String::new();
80    
81    // 生成城市名前缀
82    for _ in 0..prefix_len {
83        city.push(crate::regions::china::rand_hanzi());
84    }
85    
86    // 添加后缀
87    city.push_str(CITY_SUFFIXES.choose(&mut rng).unwrap());
88    city
89}
90
91/// 生成中国街道
92pub fn zh_street() -> String {
93    let mut rng = rand::thread_rng();
94    let prefix = STREET_PREFIXES.choose(&mut rng).unwrap();
95    let suffix = STREET_SUFFIXES.choose(&mut rng).unwrap();
96    format!("{}{}", prefix, suffix)
97}
98
99/// 生成中国完整地址
100pub fn zh_address() -> String {
101    let mut rng = rand::thread_rng();
102    let province = zh_province();
103    let city = zh_city();
104    let street = zh_street();
105    let number = rng.gen_range(1..=999);
106    
107    format!("{}{}{}{number}号", province, city, street, number = number)
108}
109
110/// 生成邮政编码
111pub fn postal_code() -> String {
112    let mut rng = rand::thread_rng();
113    // 中国邮政编码首位数字为1-8
114    let first_digit = rng.gen_range(1..=8);
115    let remaining = rng.gen_range(10000..=99999);
116    format!("{}{:05}", first_digit, remaining)
117}
118
119/// 生成美国州名
120pub fn us_state() -> String {
121    let mut rng = rand::thread_rng();
122    US_STATES.choose(&mut rng).unwrap().clone()
123}
124
125/// 生成美国城市
126pub fn us_city() -> String {
127    let mut rng = rand::thread_rng();
128    US_CITIES.choose(&mut rng).unwrap().clone()
129}
130
131/// 生成美国邮编
132pub fn us_postal_code() -> String {
133    let mut rng = rand::thread_rng();
134    format!("{:05}", rng.gen_range(10000..=99999))
135}
136
137/// 生成中国邮编(别名)
138pub fn zh_postal_code() -> String {
139    postal_code()
140}
141
142/// 生成坐标
143pub fn coordinate() -> (f64, f64) {
144    coordinates()
145}
146
147/// 生成中国坐标
148pub fn china_coordinate() -> (f64, f64) {
149    let mut rng = rand::thread_rng();
150    let lat = rng.gen_range(18.0..=54.0); // 中国纬度范围
151    let lng = rng.gen_range(73.0..=135.0); // 中国经度范围
152    (lat, lng)
153}
154
155/// 生成美国地址
156pub fn us_address() -> String {
157    let mut rng = rand::thread_rng();
158    let number = rng.gen_range(1..=9999);
159    let street_names = ["Main St", "Oak Ave", "Pine Rd", "Elm Dr", "Maple Ln"];
160    let street = street_names.choose(&mut rng).unwrap();
161    let city = us_city();
162    let state = us_state();
163    let zip = rng.gen_range(10000..=99999);
164    
165    format!("{} {}, {}, {} {}", number, street, city, state, zip)
166}
167
168/// 生成经度
169pub fn longitude() -> f64 {
170    let mut rng = rand::thread_rng();
171    rng.gen_range(-180.0..=180.0)
172}
173
174/// 生成纬度
175pub fn latitude() -> f64 {
176    let mut rng = rand::thread_rng();
177    rng.gen_range(-90.0..=90.0)
178}
179
180/// 生成坐标点
181pub fn coordinates() -> (f64, f64) {
182    (latitude(), longitude())
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188
189    #[test]
190    fn test_zh_province() {
191        let province = zh_province();
192        assert!(!province.is_empty());
193        assert!(PROVINCES.contains(&province.as_str()));
194    }
195
196    #[test]
197    fn test_zh_address() {
198        let address = zh_address();
199        assert!(!address.is_empty());
200        assert!(address.contains("号"));
201    }
202
203    #[test]
204    fn test_postal_code() {
205        let code = postal_code();
206        assert_eq!(code.len(), 6);
207        assert!(code.chars().all(|c| c.is_ascii_digit()));
208    }
209
210    #[test]
211    fn test_coordinates() {
212        let (lat, lng) = coordinates();
213
214        // 经度有效范围是[-180, 180],纬度是[-90, 90]
215        assert!(lng >= -180.0 && lng <= 180.0);
216        assert!(lat >= -90.0 && lat <= 90.0, "lat is: {}", lat);
217    }
218}