japanese_address_parser/experimental/
parser.rs

1use crate::domain::common::latlng::LatLng;
2use crate::domain::common::token::Token;
3use crate::http::client::ApiClient;
4use crate::http::reqwest_client::ReqwestApiClient;
5use serde::Serialize;
6use std::marker::PhantomData;
7
8/// Data source for Parser
9///
10/// パーサーで使用するデータソースを指定します。
11#[derive(Debug, Default)]
12pub enum DataSource {
13    /// ChimeiRuiju 住所データ
14    /// <https://github.com/Cocon/chimei-ruiju>
15    ChimeiRuiju,
16    /// Geolonia 住所データ
17    /// <https://github.com/geolonia/japanese-addresses>
18    #[default]
19    Geolonia,
20}
21
22/// Options for Parser
23///
24/// パーサーのオプションを指定します。
25/// 何も変更しない場合は`ParserOptions::default()`を使用してください。
26///
27/// # Example
28/// ```
29/// use japanese_address_parser::experimental::parser::{DataSource, Parser, ParserOptions};
30///
31/// // Customize parser
32/// let options = ParserOptions {
33///     data_source: DataSource::Geolonia,
34///     correct_incomplete_city_names: false,
35///     verbose: false,
36/// };
37///
38/// // Use default options
39/// let options = ParserOptions::default();
40/// ```
41#[derive(Debug)]
42pub struct ParserOptions {
43    /// 使用する住所データ
44    pub data_source: DataSource,
45    /// 入力された住所が不正確で市区町村名を検出できない場合、あいまい検索で市区町村名を検出します
46    pub correct_incomplete_city_names: bool,
47    /// ログの出力の有無
48    pub verbose: bool,
49}
50
51impl Default for ParserOptions {
52    fn default() -> Self {
53        Self {
54            data_source: DataSource::Geolonia,
55            correct_incomplete_city_names: true,
56            verbose: true,
57        }
58    }
59}
60
61/// Yet another address parser(experimental)
62///
63/// 新型の住所パーサーです。試験的な機能のため、予告なしに破壊的変更が入る可能性があります。
64/// 住所マスタとのデータ通信に使用する`ApiClient`を指定したい場合は`Parser#new`メソッドを使用してください。
65///
66/// # Example
67/// ```
68/// use japanese_address_parser::experimental::parser::Parser;
69/// use japanese_address_parser::http::reqwest_client::ReqwestApiClient;
70///
71/// // デフォルトの`ApiClient`を使用する場合
72/// let parser = Parser::default();
73///
74/// // `ApiClient`を指定する場合
75/// let parser = Parser::<ReqwestApiClient>::new();
76/// ```
77#[derive(Debug)]
78pub struct Parser<Client: ApiClient = ReqwestApiClient> {
79    _client: PhantomData<Client>,
80}
81
82impl Default for Parser {
83    fn default() -> Self {
84        Parser {
85            _client: Default::default(),
86        }
87    }
88}
89
90impl<Client: ApiClient> Parser<Client> {
91    pub fn new() -> Self {
92        Parser {
93            _client: PhantomData::<Client>,
94        }
95    }
96    /// Parse address into [ParsedAddress].
97    ///
98    /// 住所をパースし、[ParsedAddress]を返します。
99    ///
100    /// # Example
101    /// ```
102    /// use japanese_address_parser::experimental::parser::Parser;
103    ///
104    /// async fn example() {
105    ///     let parser = Parser::default();
106    ///     let result = parser.parse("埼玉県所沢市上山口2135").await;
107    ///     assert_eq!(result.prefecture, "埼玉県");
108    ///     assert_eq!(result.city, "所沢市");
109    ///     assert_eq!(result.town, "上山口");
110    ///     assert_eq!(result.rest, "2135");
111    ///     assert_eq!(result.metadata.depth, 3);
112    /// }
113    /// ```
114    pub async fn parse(&self, address: &str) -> ParsedAddress {
115        self.parse_with_options(address, &ParserOptions::default())
116            .await
117    }
118
119    /// Parse address into [ParsedAddress] with options.
120    ///
121    /// オプションを指定して住所をパースします。[ParsedAddress]を返します。
122    ///
123    /// # Example
124    /// ```
125    /// use japanese_address_parser::experimental::parser::{DataSource, Parser, ParserOptions};
126    ///
127    ///  async fn example() {
128    ///     let parser = Parser::default();
129    ///     let parser_options = &ParserOptions {
130    ///             data_source: DataSource::ChimeiRuiju,
131    ///             correct_incomplete_city_names: true,
132    ///             verbose: true,
133    ///     };
134    ///     let result = parser.parse_with_options("東京都中央区銀座1丁目1-1", parser_options).await;
135    ///     assert_eq!(result.prefecture, "東京都");
136    ///     assert_eq!(result.city, "中央区");
137    ///     assert_eq!(result.town, "銀座一丁目");
138    ///     assert_eq!(result.rest, "1-1");
139    ///     assert_eq!(result.metadata.depth, 3);
140    /// }
141    /// ```
142    pub async fn parse_with_options(
143        &self,
144        address: &str,
145        options: &ParserOptions,
146    ) -> ParsedAddress {
147        match options.data_source {
148            DataSource::ChimeiRuiju => {
149                ParsedAddress::from(self.parse_with_chimeiruiju(address, options).await)
150            }
151            DataSource::Geolonia => {
152                ParsedAddress::from(self.parse_with_geolonia(address, options).await)
153            }
154        }
155    }
156}
157
158#[derive(Debug, PartialEq, Serialize)]
159pub struct ParsedAddress {
160    /// 都道府県名
161    pub prefecture: String,
162    /// 市区町村名
163    pub city: String,
164    /// 町名
165    pub town: String,
166    /// それ以降
167    pub rest: String,
168    /// メタデータ
169    pub metadata: Metadata,
170}
171
172#[derive(Debug, PartialEq, Serialize)]
173pub struct Metadata {
174    /// 緯度
175    ///
176    /// 住所のパースに成功し、緯度経度の情報が取得できる場合、緯度を返します。
177    /// 緯度経度の情報はあくまで検出できた地域の代表点を表すものであり、入力された住所の実際の位置とは必ずしも一致しないことに注意してください。
178    pub latitude: Option<f64>,
179    /// 経度
180    ///
181    /// 住所のパースに成功し、緯度経度の情報が取得できる場合、経度を返します。
182    /// 緯度経度の情報はあくまで検出できた地域の代表点を表すものであり、入力された住所の実際の位置とは必ずしも一致しないことに注意してください。
183    pub longitude: Option<f64>,
184    /// パース処理の深度
185    ///
186    /// - `0`: 何も検出できなかった場合
187    /// - `1`: 都道府県名までは検出できた場合
188    /// - `2`: 市区町村名までは検出できた場合
189    /// - `3`: 町名まで検出できた場合
190    pub depth: u8,
191}
192
193impl From<Vec<Token>> for ParsedAddress {
194    fn from(mut value: Vec<Token>) -> Self {
195        // 現在の実装では`Tokenizer`からもたらされる`Vec<Token>`は要素が順序よく並んでいるため、本来以下の実装は不要である
196        // ただし、ソート済みになっていることがコード上保証できないのが気になるため、ここでソートを行なっている。
197        value.sort_by(|a, b| a.partial_cmp(b).unwrap());
198
199        let mut parsed_address = ParsedAddress {
200            prefecture: "".to_string(),
201            city: "".to_string(),
202            town: "".to_string(),
203            rest: "".to_string(),
204            metadata: Metadata {
205                latitude: None,
206                longitude: None,
207                depth: 0,
208            },
209        };
210
211        for token in value {
212            match token {
213                Token::Prefecture(prefecture_name) => {
214                    parsed_address.prefecture = prefecture_name;
215                    parsed_address.metadata.depth = 1;
216                }
217                Token::City(city_name) => {
218                    parsed_address.city = city_name;
219                    parsed_address.metadata.depth = 2;
220                }
221                Token::Town(town_name) => {
222                    parsed_address.town = town_name;
223                    parsed_address.metadata.depth = 3;
224                }
225                Token::Rest(rest) => {
226                    parsed_address.rest = rest;
227                }
228            }
229        }
230
231        parsed_address
232    }
233}
234
235impl From<(Vec<Token>, Option<LatLng>)> for ParsedAddress {
236    fn from((tokens, lat_lng): (Vec<Token>, Option<LatLng>)) -> Self {
237        let mut parsed_address = ParsedAddress::from(tokens);
238        if let Some(lat_lng) = lat_lng {
239            parsed_address.metadata.longitude = Some(lat_lng.longitude);
240            parsed_address.metadata.latitude = Some(lat_lng.latitude);
241        }
242        parsed_address
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use crate::domain::common::latlng::LatLng;
249    use crate::domain::common::token::Token;
250    use crate::experimental::parser::{Metadata, ParsedAddress};
251
252    #[test]
253    fn conversion_depthが0() {
254        let tokens = vec![Token::Rest(
255            "新浜県新浜市ニューポートシティ1-1-1".to_string(),
256        )];
257        let parsed_address = ParsedAddress::from(tokens);
258        assert_eq!(
259            parsed_address,
260            ParsedAddress {
261                prefecture: "".to_string(),
262                city: "".to_string(),
263                town: "".to_string(),
264                rest: "新浜県新浜市ニューポートシティ1-1-1".to_string(),
265                metadata: Metadata {
266                    latitude: None,
267                    longitude: None,
268                    depth: 0,
269                },
270            }
271        )
272    }
273
274    #[test]
275    fn conversion_depthが1() {
276        let tokens = vec![
277            Token::Prefecture("東京都".to_string()),
278            Token::Rest("".to_string()),
279        ];
280        let lat_lng = Some(LatLng {
281            latitude: 139.748264,
282            longitude: 35.68532,
283        });
284        let parsed_address = ParsedAddress::from((tokens, lat_lng));
285        assert_eq!(
286            parsed_address,
287            ParsedAddress {
288                prefecture: "東京都".to_string(),
289                city: "".to_string(),
290                town: "".to_string(),
291                rest: "".to_string(),
292                metadata: Metadata {
293                    latitude: Some(139.748264),
294                    longitude: Some(35.68532),
295                    depth: 1,
296                },
297            }
298        )
299    }
300
301    #[test]
302    fn conversion_depthが2() {
303        let tokens = vec![
304            Token::Prefecture("東京都".to_string()),
305            Token::City("台東区".to_string()),
306            Token::Rest("".to_string()),
307        ];
308        let lat_lng = Some(LatLng {
309            latitude: 139.764379,
310            longitude: 35.711162,
311        });
312        let parsed_address = ParsedAddress::from((tokens, lat_lng));
313        assert_eq!(
314            parsed_address,
315            ParsedAddress {
316                prefecture: "東京都".to_string(),
317                city: "台東区".to_string(),
318                town: "".to_string(),
319                rest: "".to_string(),
320                metadata: Metadata {
321                    latitude: Some(139.764379),
322                    longitude: Some(35.711162),
323                    depth: 2,
324                },
325            }
326        )
327    }
328
329    #[test]
330    fn conversion_depthが3() {
331        let tokens = vec![
332            Token::Prefecture("東京都".to_string()),
333            Token::City("文京区".to_string()),
334            Token::Town("本駒込六丁目".to_string()),
335            Token::Rest("16-3".to_string()),
336        ];
337        let lat_lng = Some(LatLng {
338            latitude: 139.738043,
339            longitude: 35.72791,
340        });
341        let parsed_address = ParsedAddress::from((tokens, lat_lng));
342        assert_eq!(
343            parsed_address,
344            ParsedAddress {
345                prefecture: "東京都".to_string(),
346                city: "文京区".to_string(),
347                town: "本駒込六丁目".to_string(),
348                rest: "16-3".to_string(),
349                metadata: Metadata {
350                    latitude: Some(139.738043),
351                    longitude: Some(35.72791),
352                    depth: 3,
353                },
354            }
355        )
356    }
357}