japanese_address_parser/experimental/
parser.rs1use 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#[derive(Debug, Default)]
12pub enum DataSource {
13 ChimeiRuiju,
16 #[default]
19 Geolonia,
20}
21
22#[derive(Debug)]
42pub struct ParserOptions {
43 pub data_source: DataSource,
45 pub correct_incomplete_city_names: bool,
47 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#[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 pub async fn parse(&self, address: &str) -> ParsedAddress {
115 self.parse_with_options(address, &ParserOptions::default())
116 .await
117 }
118
119 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 pub prefecture: String,
162 pub city: String,
164 pub town: String,
166 pub rest: String,
168 pub metadata: Metadata,
170}
171
172#[derive(Debug, PartialEq, Serialize)]
173pub struct Metadata {
174 pub latitude: Option<f64>,
179 pub longitude: Option<f64>,
184 pub depth: u8,
191}
192
193impl From<Vec<Token>> for ParsedAddress {
194 fn from(mut value: Vec<Token>) -> Self {
195 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}