japanese_address_parser/
parser.rs

1use std::sync::Arc;
2
3use crate::domain::common::token::Token;
4use crate::domain::geolonia::entity::Address;
5use crate::domain::geolonia::error::{Error, ParseErrorKind};
6use crate::http::reqwest_client::ReqwestApiClient;
7use crate::interactor::geolonia::{GeoloniaInteractor, GeoloniaInteractorImpl};
8use crate::tokenizer::{End, Tokenizer};
9use serde::Serialize;
10
11impl From<Tokenizer<End>> for Address {
12    fn from(value: Tokenizer<End>) -> Self {
13        let mut address = Address::new("", "", "", "");
14        for token in value.tokens {
15            match token {
16                Token::Prefecture(prefecture_name) => address.prefecture = prefecture_name,
17                Token::City(city_name) => address.city = city_name,
18                Token::Town(town_name) => address.town = town_name,
19                Token::Rest(rest) => address.rest = rest,
20            }
21        }
22        address
23    }
24}
25
26/// An asynchronous `Parser` to process addresses.
27///
28/// # Example
29/// ```
30/// use japanese_address_parser::parser::Parser;
31///
32/// async fn example() {
33///     let parser : Parser = Default::default();
34///     let result = parser.parse("東京都新宿区西新宿2-8-1").await;
35///     println!("{:?}", result);
36/// }
37/// ```
38pub struct Parser {
39    interactor: Arc<GeoloniaInteractorImpl<ReqwestApiClient>>,
40}
41
42impl Default for Parser {
43    /// Constructs a new `Parser`.
44    fn default() -> Self {
45        Self {
46            interactor: Arc::new(Default::default()),
47        }
48    }
49}
50
51impl Parser {
52    /// Parses the given `address` asynchronously.
53    pub async fn parse(&self, address: &str) -> ParseResult {
54        let interactor = self.interactor.clone();
55        let tokenizer = Tokenizer::new(address);
56        // 都道府県を特定
57        let (prefecture, tokenizer) = match tokenizer.read_prefecture() {
58            Ok(found) => found,
59            Err(tokenizer) => {
60                return ParseResult {
61                    address: Address::from(tokenizer),
62                    error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)),
63                }
64            }
65        };
66        // その都道府県の市町村名リストを取得
67        let prefecture_master = match interactor.get_prefecture_master(prefecture.name_ja()).await {
68            Err(error) => {
69                return ParseResult {
70                    address: Address::from(tokenizer.finish()),
71                    error: Some(error),
72                };
73            }
74            Ok(result) => result,
75        };
76        // 市町村名を特定
77        let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) {
78            Ok(found) => found,
79            Err(not_found) => {
80                // 市区町村が特定できない場合かつフィーチャフラグが有効な場合、郡名が抜けている可能性を検討
81                match not_found.read_city_with_county_name_completion(&prefecture_master.cities) {
82                    Ok(found) if cfg!(feature = "city-name-correction") => found,
83                    _ => {
84                        // それでも見つからない場合は終了
85                        return ParseResult {
86                            address: Address::from(tokenizer.finish()),
87                            error: Some(Error::new_parse_error(ParseErrorKind::City)),
88                        };
89                    }
90                }
91            }
92        };
93        // その市町村の町名リストを取得
94        let city = match interactor
95            .get_city_master(prefecture.name_ja(), &city_name)
96            .await
97        {
98            Err(error) => {
99                return ParseResult {
100                    address: Address::from(tokenizer.finish()),
101                    error: Some(error),
102                };
103            }
104            Ok(result) => result,
105        };
106        // 町名を特定
107        let Ok((_, tokenizer)) =
108            tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect())
109        else {
110            return ParseResult {
111                address: Address::from(tokenizer.finish()),
112                error: Some(Error::new_parse_error(ParseErrorKind::Town)),
113            };
114        };
115
116        ParseResult {
117            address: Address::from(tokenizer.finish()),
118            error: None,
119        }
120    }
121
122    /// Parses the given `address` synchronously.
123    #[cfg(feature = "blocking")]
124    pub fn parse_blocking(&self, address: &str) -> ParseResult {
125        let interactor = self.interactor.clone();
126        let tokenizer = Tokenizer::new(address);
127        let (prefecture, tokenizer) = match tokenizer.read_prefecture() {
128            Ok(found) => found,
129            Err(tokenizer) => {
130                return ParseResult {
131                    address: Address::from(tokenizer),
132                    error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)),
133                }
134            }
135        };
136        let prefecture_master =
137            match interactor.get_blocking_prefecture_master(prefecture.name_ja()) {
138                Err(error) => {
139                    return ParseResult {
140                        address: Address::from(tokenizer.finish()),
141                        error: Some(error),
142                    };
143                }
144                Ok(result) => result,
145            };
146        let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) {
147            Ok(found) => found,
148            Err(not_found) => {
149                match not_found.read_city_with_county_name_completion(&prefecture_master.cities) {
150                    Ok(found) if cfg!(feature = "city-name-correction") => found,
151                    _ => {
152                        return ParseResult {
153                            address: Address::from(tokenizer.finish()),
154                            error: Some(Error::new_parse_error(ParseErrorKind::City)),
155                        };
156                    }
157                }
158            }
159        };
160        let city = match interactor.get_blocking_city_master(prefecture.name_ja(), &city_name) {
161            Err(error) => {
162                return ParseResult {
163                    address: Address::from(tokenizer.finish()),
164                    error: Some(error),
165                };
166            }
167            Ok(result) => result,
168        };
169        let Ok((_, tokenizer)) =
170            tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect())
171        else {
172            return ParseResult {
173                address: Address::from(tokenizer.finish()),
174                error: Some(Error::new_parse_error(ParseErrorKind::Town)),
175            };
176        };
177
178        ParseResult {
179            address: Address::from(tokenizer.finish()),
180            error: None,
181        }
182    }
183}
184
185#[cfg(all(test, not(feature = "blocking")))]
186mod tests {
187    use crate::domain::geolonia::error::ParseErrorKind;
188    use crate::parser::Parser;
189    use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
190
191    #[tokio::test]
192    async fn 都道府県名が誤っている場合() {
193        let parser = Parser::default();
194        let result = parser.parse("青盛県青森市長島1丁目1−1").await;
195        assert_eq!(result.address.prefecture, "");
196        assert_eq!(result.address.city, "");
197        assert_eq!(result.address.town, "");
198        assert_eq!(result.address.rest, "青盛県青森市長島1丁目1−1");
199        assert_eq!(result.error.is_some(), true);
200        assert_eq!(
201            result.error.unwrap().error_message,
202            ParseErrorKind::Prefecture.to_string()
203        );
204    }
205
206    #[tokio::test]
207    async fn 市区町村名が誤っている場合() {
208        let parser = Parser::default();
209        let result = parser.parse("青森県青盛市長島1丁目1−1").await;
210        assert_eq!(result.address.prefecture, "青森県");
211        assert_eq!(result.address.city, "");
212        assert_eq!(result.address.town, "");
213        assert_eq!(result.address.rest, "青盛市長島1丁目1−1");
214        assert_eq!(result.error.is_some(), true);
215        assert_eq!(
216            result.error.unwrap().error_message,
217            ParseErrorKind::City.to_string()
218        );
219    }
220
221    #[tokio::test]
222    async fn 町名が誤っている場合() {
223        let parser = Parser::default();
224        let result = parser.parse("青森県青森市永嶋1丁目1−1").await;
225        assert_eq!(result.address.prefecture, "青森県");
226        assert_eq!(result.address.city, "青森市");
227        assert_eq!(result.address.town, "");
228        assert_eq!(result.address.rest, "永嶋1丁目1−1");
229        assert_eq!(result.error.is_some(), true);
230        assert_eq!(
231            result.error.unwrap().error_message,
232            ParseErrorKind::Town.to_string()
233        );
234    }
235
236    wasm_bindgen_test_configure!(run_in_browser);
237
238    #[wasm_bindgen_test]
239    async fn parse_wasm_success() {
240        let parser = Parser::default();
241        let result = parser.parse("兵庫県淡路市生穂新島8番地").await;
242        assert_eq!(result.address.prefecture, "兵庫県".to_string());
243        assert_eq!(result.address.city, "淡路市".to_string());
244        assert_eq!(result.address.town, "生穂".to_string());
245        assert_eq!(result.address.rest, "新島8番地".to_string());
246        assert_eq!(result.error, None);
247    }
248}
249
250#[cfg(all(test, feature = "blocking"))]
251mod blocking_tests {
252    use crate::domain::geolonia::error::ParseErrorKind;
253    use crate::parser::Parser;
254
255    #[test]
256    fn parse_blocking_success_埼玉県秩父市熊木町8番15号() {
257        let parser = Parser::default();
258        let result = parser.parse_blocking("埼玉県秩父市熊木町8番15号");
259        assert_eq!(result.address.prefecture, "埼玉県");
260        assert_eq!(result.address.city, "秩父市");
261        assert_eq!(result.address.town, "熊木町");
262        assert_eq!(result.address.rest, "8番15号");
263        assert_eq!(result.error, None);
264    }
265
266    #[test]
267    fn parse_blocking_fail_市町村名が間違っている場合() {
268        let parser = Parser::default();
269        let result = parser.parse_blocking("埼玉県秩父柿熊木町8番15号");
270        assert_eq!(result.address.prefecture, "埼玉県");
271        assert_eq!(result.address.city, "");
272        assert_eq!(result.address.town, "");
273        assert_eq!(result.address.rest, "秩父柿熊木町8番15号");
274        assert_eq!(
275            result.error.unwrap().error_message,
276            ParseErrorKind::City.to_string()
277        );
278    }
279}
280
281#[derive(Serialize, PartialEq, Debug)]
282pub struct ParseResult {
283    pub address: Address,
284    pub error: Option<Error>,
285}