diff --git a/.github/workflows/python-build-check.yaml b/.github/workflows/python-build-check.yaml index df44e5fa..41790d9c 100644 --- a/.github/workflows/python-build-check.yaml +++ b/.github/workflows/python-build-check.yaml @@ -27,6 +27,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: x86_64 args: --release --out dist --zig working-directory: python @@ -50,6 +51,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: x64 args: --release --out dist working-directory: python @@ -71,6 +73,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: aarch64 args: --release --out dist working-directory: python @@ -89,6 +92,7 @@ jobs: - name: Build sdist uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 command: sdist args: --out dist working-directory: python diff --git a/.github/workflows/upload-pypi-org.yaml b/.github/workflows/upload-pypi-org.yaml index 8b7626bd..17b39f9d 100644 --- a/.github/workflows/upload-pypi-org.yaml +++ b/.github/workflows/upload-pypi-org.yaml @@ -38,6 +38,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: ${{ matrix.platform.target }} args: --release --out dist --zig working-directory: python @@ -67,6 +68,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: ${{ matrix.platform.target }} args: --release --out dist working-directory: python @@ -94,6 +96,7 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 target: ${{ matrix.platform.target }} args: --release --out dist working-directory: python @@ -111,6 +114,7 @@ jobs: - name: Build sdist uses: PyO3/maturin-action@v1 with: + maturin-version: 1.7.8 command: sdist args: --out dist working-directory: python @@ -133,5 +137,6 @@ jobs: MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} MATURIN_REPOSITORY: "pypi" # test.pypi.orgにアップロードする際は"testpypi"を設定する with: + maturin-version: 1.7.8 command: upload args: --non-interactive --skip-existing wheels-*/* diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..caf69432 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +マイナーバージョンアップやメジャーバージョンアップの際に発生する破壊的変更についてこのファイルに記載します。 +それ以外の変更については[リリースノート](https://github.com/YuukiToriyama/japanese-address-parser/releases)を参照ください。 + +## v0.2.0 + +### 非推奨に指定していたモジュール、関数を削除しました([#532](https://github.com/YuukiToriyama/japanese-address-parser/pull/532))。 + +- `japanese_address_parser::parser::parse`や`japanese_address_parser::parser::parse_blocking`を使用しているコードは動かなくなります。 + `japanese_address_parser::parser::Parser`の使用を検討してください。 +- また、`japanese_address_parser::entity::Address`は`japanese_address_parser::domain::geolonia::Address`に移動しました。 + そのままだと動かないので、use文を修正してください。 diff --git a/Cargo.toml b/Cargo.toml index 59c3baa9..07da6ea6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,9 @@ members = [ resolver = "2" [workspace.package] -version = "0.1.24" +version = "0.2.0" edition = "2021" -description = "A Rust Library to parse japanese addresses." +description = "A library for processing addresses of Japan" repository = "https://github.com/YuukiToriyama/japanese-address-parser" authors = ["Yuuki Toriyama "] license = "MIT" @@ -19,8 +19,8 @@ categories = ["parser-implementations", "wasm"] [workspace.dependencies] log = "0.4.22" -serde = { version = "1.0.192", features = ["derive"] } -tokio = { version = "1.38.0", features = ["rt", "macros"] } -wasm-bindgen = "0.2.92" -wasm-bindgen-futures = "0.4.42" -wasm-bindgen-test = "0.3.42" +serde = { version = "1.0.215", features = ["derive"] } +tokio = { version = "1.41.1", features = ["rt", "macros"] } +wasm-bindgen = "0.2.97" +wasm-bindgen-futures = "0.4.47" +wasm-bindgen-test = "0.3.47" diff --git a/LICENSE b/LICENSE index 09fdfd2d..2c98bacc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 ToriChan +Copyright (c) 2023-2024 Yuuki Toriyama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index cbd0f7eb..6c668d80 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Add the following to your `Cargo.toml`. ```toml [dependencies] -japanese-address-parser = "0.1" +japanese-address-parser = "0.2" ``` ### Async Version diff --git a/core/Cargo.toml b/core/Cargo.toml index 0cf422a0..183d1a08 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -23,23 +23,21 @@ eliminate-whitespaces = [] experimental = [] [dependencies] -itertools = "0.13.0" # 互換性のために残してあるが、`core::parser::adapter`を削除する際に忘れずに削除する log.workspace = true rapidfuzz = "0.5.0" -regex = { version = "1.10.6", default-features = false, features = ["std", "unicode-perl"] } +regex = { version = "1.11.1", default-features = false, features = ["std", "unicode-perl"] } serde.workspace = true -reqwest = { version = "0.12.5", default-features = false, features = ["json", "rustls-tls"] } -js-sys = "0.3.67" -thiserror = "1.0.63" -jisx0401 = "0.1.0-beta.3" +reqwest = { version = "0.12.9", default-features = false, features = ["json", "rustls-tls"] } +js-sys = "0.3.74" +thiserror = "2.0.3" +jisx0401 = "0.1.1" [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["html_reports"] } tokio.workspace = true wasm-bindgen-test = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -mockito = "1.4.0" # mockitoがwasm32に対応していないため +mockito = "1.6.1" # mockitoがwasm32に対応していないため [package.metadata.docs.rs] all-features = true diff --git a/core/src/adapter/orthographical_variant_adapter.rs b/core/src/adapter/orthographical_variant_adapter.rs index 7fba398a..41ef50e6 100644 --- a/core/src/adapter/orthographical_variant_adapter.rs +++ b/core/src/adapter/orthographical_variant_adapter.rs @@ -10,6 +10,7 @@ pub enum OrthographicalVariant { 竈, 嶋, 舘, + 鰺, 脊, 渕, 己, @@ -28,6 +29,14 @@ pub enum OrthographicalVariant { 濱, 祗, 曾, + 國, + 鉋, + 鷆, + 斑, + 櫻, + 櫟, + 冨, + 諫, } impl OrthographicalVariant { @@ -43,6 +52,7 @@ impl OrthographicalVariant { OrthographicalVariant::竈 => &['竈', '竃', '釜'], OrthographicalVariant::嶋 => &['嶋', '島'], OrthographicalVariant::舘 => &['舘', '館'], + OrthographicalVariant::鰺 => &['鰺', '鯵'], OrthographicalVariant::脊 => &['脊', '背'], OrthographicalVariant::渕 => &['渕', '淵'], OrthographicalVariant::己 => &['己', '巳'], @@ -61,6 +71,14 @@ impl OrthographicalVariant { OrthographicalVariant::濱 => &['濱', '浜'], OrthographicalVariant::祗 => &['祗', '祇'], OrthographicalVariant::曾 => &['曾', '曽'], + OrthographicalVariant::國 => &['國', '国'], + OrthographicalVariant::鉋 => &['鉋', '飽'], + OrthographicalVariant::鷆 => &['鷆', '鷏'], + OrthographicalVariant::斑 => &['斑', '班'], + OrthographicalVariant::櫻 => &['櫻', '桜'], + OrthographicalVariant::櫟 => &['櫟', '擽'], + OrthographicalVariant::冨 => &['冨', '富'], + OrthographicalVariant::諫 => &['諫', '諌'], } } diff --git a/core/src/api.rs b/core/src/api.rs deleted file mode 100644 index 0c9696c5..00000000 --- a/core/src/api.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![allow(deprecated)] -pub use crate::repository::geolonia::city_master_api; -pub use crate::repository::geolonia::prefecture_master_api; - -use crate::domain::geolonia::entity::{City, Prefecture}; -use crate::domain::geolonia::error::Error; -use crate::repository::geolonia::city_master_api::CityMasterApi; -use crate::repository::geolonia::prefecture_master_api::PrefectureMasterApi; - -#[derive(Default)] -pub struct AsyncApi { - pub prefecture_master_api: PrefectureMasterApi, - pub city_master_api: CityMasterApi, -} - -impl AsyncApi { - pub async fn get_prefecture_master(&self, prefecture_name: &str) -> Result { - self.prefecture_master_api.get(prefecture_name).await - } - - pub async fn get_city_master( - &self, - prefecture_name: &str, - city_name: &str, - ) -> Result { - self.city_master_api.get(prefecture_name, city_name).await - } -} - -#[cfg(feature = "blocking")] -#[derive(Default)] -pub struct BlockingApi { - prefecture_master_api: PrefectureMasterApi, - city_master_api: CityMasterApi, -} - -#[cfg(feature = "blocking")] -impl BlockingApi { - pub fn get_prefecture_master(&self, prefecture_name: &str) -> Result { - self.prefecture_master_api.get_blocking(prefecture_name) - } - - pub fn get_city_master(&self, prefecture_name: &str, city_name: &str) -> Result { - self.city_master_api - .get_blocking(prefecture_name, city_name) - } -} diff --git a/core/src/domain.rs b/core/src/domain.rs index d1184822..9d94f776 100644 --- a/core/src/domain.rs +++ b/core/src/domain.rs @@ -1,4 +1,4 @@ #[cfg(feature = "experimental")] -pub mod chimei_ruiju; -pub mod common; +pub(crate) mod chimei_ruiju; +pub(crate) mod common; pub mod geolonia; diff --git a/core/src/domain/geolonia/entity.rs b/core/src/domain/geolonia/entity.rs index 63f81573..cf5994b3 100644 --- a/core/src/domain/geolonia/entity.rs +++ b/core/src/domain/geolonia/entity.rs @@ -1,29 +1,20 @@ use serde::{Deserialize, Serialize}; #[derive(Deserialize, PartialEq, Debug)] -pub struct Prefecture { +pub(crate) struct Prefecture { pub name: String, pub cities: Vec, } -impl Prefecture { - // 主にテストコードで使用する - pub fn new(prefecture_name: &str, city_names: Vec<&str>) -> Self { - Prefecture { - name: prefecture_name.to_string(), - cities: city_names.iter().map(|s| s.to_string()).collect(), - } - } -} - #[derive(Debug)] -pub struct City { +pub(crate) struct City { + #[allow(dead_code)] pub name: String, pub towns: Vec, } #[derive(PartialEq, Deserialize, Debug)] -pub struct Town { +pub(crate) struct Town { #[serde(alias = "town")] pub name: String, pub koaza: String, @@ -32,18 +23,6 @@ pub struct Town { pub lng: Option, } -impl Town { - // 主にテストコードで使用する - pub fn new(town_name: &str, koaza_name: &str, lat: f32, lng: f32) -> Self { - Town { - name: town_name.to_string(), - koaza: koaza_name.to_string(), - lat: Some(lat), - lng: Some(lng), - } - } -} - #[derive(Serialize, PartialEq, Debug)] pub struct Address { pub prefecture: String, @@ -53,7 +32,12 @@ pub struct Address { } impl Address { - pub fn new(prefecture_name: &str, city_name: &str, town_name: &str, rest_name: &str) -> Self { + pub(crate) fn new( + prefecture_name: &str, + city_name: &str, + town_name: &str, + rest_name: &str, + ) -> Self { Address { prefecture: prefecture_name.to_string(), city: city_name.to_string(), @@ -63,10 +47,10 @@ impl Address { } } -#[doc(hidden)] +#[cfg(test)] impl Prefecture { /// only for testing - pub fn yamagata() -> Self { + pub(crate) fn yamagata() -> Self { Prefecture { name: "山形県".to_string(), cities: vec![ @@ -110,7 +94,7 @@ impl Prefecture { } /// only for testing - pub fn fukushima() -> Self { + pub(crate) fn fukushima() -> Self { Prefecture { name: "福島県".to_string(), cities: vec![ @@ -178,7 +162,7 @@ impl Prefecture { } /// only for testing - pub fn fukui() -> Self { + pub(crate) fn fukui() -> Self { Prefecture { name: "福井県".to_string(), cities: vec![ @@ -204,7 +188,7 @@ impl Prefecture { } /// only for testing - pub fn saga() -> Self { + pub(crate) fn saga() -> Self { Prefecture { name: "佐賀県".to_string(), cities: vec![ diff --git a/core/src/domain/geolonia/error.rs b/core/src/domain/geolonia/error.rs index 66aed401..b73f61aa 100644 --- a/core/src/domain/geolonia/error.rs +++ b/core/src/domain/geolonia/error.rs @@ -9,13 +9,13 @@ pub struct Error { } impl Error { - pub fn new_parse_error(parse_error_kind: ParseErrorKind) -> Self { + pub(crate) fn new_parse_error(parse_error_kind: ParseErrorKind) -> Self { Error { error_type: "ParseError".to_string(), error_message: parse_error_kind.to_string(), } } - pub fn new_api_error(api_error_kind: ApiErrorKind) -> Self { + pub(crate) fn new_api_error(api_error_kind: ApiErrorKind) -> Self { let error_message = match api_error_kind { ApiErrorKind::Fetch(url) => format!("{}を取得できませんでした", url), ApiErrorKind::Deserialize(url) => format!("{}のデシリアライズに失敗しました", url), @@ -27,7 +27,7 @@ impl Error { } } -pub enum ParseErrorKind { +pub(crate) enum ParseErrorKind { Prefecture, City, Town, @@ -44,7 +44,7 @@ impl Display for ParseErrorKind { } } -pub enum ApiErrorKind { +pub(crate) enum ApiErrorKind { Fetch(String), Deserialize(String), } diff --git a/core/src/entity.rs b/core/src/entity.rs deleted file mode 100644 index cdcbf8bb..00000000 --- a/core/src/entity.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use crate::domain::geolonia::entity::Address; -pub use crate::domain::geolonia::entity::City; -pub use crate::domain::geolonia::entity::Prefecture; -pub use crate::domain::geolonia::entity::Town; -pub use crate::parser::ParseResult; diff --git a/core/src/lib.rs b/core/src/lib.rs index 73b3643a..83feb51d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -14,11 +14,7 @@ compile_error! { } mod adapter; -#[deprecated(since = "0.1.23", note = "This module will be deleted in v0.2")] -pub mod api; -pub(crate) mod domain; -#[deprecated(since = "0.1.6", note = "This module will be deleted in v0.2")] -pub mod entity; +pub mod domain; #[cfg(feature = "experimental")] #[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pub mod experimental; diff --git a/core/src/parser.rs b/core/src/parser.rs index 7173de49..79619f6f 100644 --- a/core/src/parser.rs +++ b/core/src/parser.rs @@ -1,9 +1,5 @@ -#![allow(deprecated)] use std::sync::Arc; -use crate::api::AsyncApi; -#[cfg(feature = "blocking")] -use crate::api::BlockingApi; use crate::domain::common::token::Token; use crate::domain::geolonia::entity::Address; use crate::domain::geolonia::error::{Error, ParseErrorKind}; @@ -11,9 +7,6 @@ use crate::interactor::geolonia::{GeoloniaInteractor, GeoloniaInteractorImpl}; use crate::tokenizer::{End, Tokenizer}; use serde::Serialize; -#[deprecated(since = "0.1.24", note = "This module will be deleted in v0.2")] -pub mod adapter; - impl From> for Address { fn from(value: Tokenizer) -> Self { let mut address = Address::new("", "", "", ""); @@ -188,75 +181,6 @@ impl Parser { } } -/// A function to parse the given address asynchronously. -/// -/// publicにしていますが、直接の使用は推奨されません。[Parser]の利用を検討してください。 -#[deprecated(since = "0.1.23", note = "This module will be deleted in v0.2")] -pub async fn parse(api: Arc, input: &str) -> ParseResult { - let tokenizer = Tokenizer::new(input); - // 都道府県を特定 - let (prefecture, tokenizer) = match tokenizer.read_prefecture() { - Ok(found) => found, - Err(tokenizer) => { - return ParseResult { - address: Address::from(tokenizer), - error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)), - } - } - }; - // その都道府県の市町村名リストを取得 - let prefecture_master = match api.get_prefecture_master(prefecture.name_ja()).await { - Err(error) => { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(error), - }; - } - Ok(result) => result, - }; - // 市町村名を特定 - let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) { - Ok(found) => found, - Err(not_found) => { - // 市区町村が特定できない場合かつフィーチャフラグが有効な場合、郡名が抜けている可能性を検討 - match not_found.read_city_with_county_name_completion(&prefecture_master.cities) { - Ok(found) if cfg!(feature = "city-name-correction") => found, - _ => { - // それでも見つからない場合は終了 - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(Error::new_parse_error(ParseErrorKind::City)), - }; - } - } - } - }; - // その市町村の町名リストを取得 - let city = match api.get_city_master(prefecture.name_ja(), &city_name).await { - Err(error) => { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(error), - }; - } - Ok(result) => result, - }; - // 町名を特定 - let Ok((_, tokenizer)) = - tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect()) - else { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(Error::new_parse_error(ParseErrorKind::Town)), - }; - }; - - ParseResult { - address: Address::from(tokenizer.finish()), - error: None, - } -} - #[cfg(all(test, not(feature = "blocking")))] mod tests { use crate::domain::geolonia::error::ParseErrorKind; @@ -322,69 +246,6 @@ mod tests { } } -/// A function to parse the given address synchronously. -/// -/// publicにしていますが、直接の使用は推奨されません。[Parser]の利用を検討してください。 -#[cfg(feature = "blocking")] -#[deprecated(since = "0.1.23", note = "This module will be deleted in v0.2")] -pub fn parse_blocking(api: Arc, input: &str) -> ParseResult { - let tokenizer = Tokenizer::new(input); - let (prefecture, tokenizer) = match tokenizer.read_prefecture() { - Ok(found) => found, - Err(tokenizer) => { - return ParseResult { - address: Address::from(tokenizer), - error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)), - } - } - }; - let prefecture_master = match api.get_prefecture_master(prefecture.name_ja()) { - Err(error) => { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(error), - }; - } - Ok(result) => result, - }; - let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) { - Ok(found) => found, - Err(not_found) => { - match not_found.read_city_with_county_name_completion(&prefecture_master.cities) { - Ok(found) if cfg!(feature = "city-name-correction") => found, - _ => { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(Error::new_parse_error(ParseErrorKind::City)), - }; - } - } - } - }; - let city = match api.get_city_master(prefecture.name_ja(), &city_name) { - Err(error) => { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(error), - }; - } - Ok(result) => result, - }; - let Ok((_, tokenizer)) = - tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect()) - else { - return ParseResult { - address: Address::from(tokenizer.finish()), - error: Some(Error::new_parse_error(ParseErrorKind::Town)), - }; - }; - - ParseResult { - address: Address::from(tokenizer.finish()), - error: None, - } -} - #[cfg(all(test, feature = "blocking"))] mod blocking_tests { use crate::domain::geolonia::error::ParseErrorKind; diff --git a/core/src/parser/adapter.rs b/core/src/parser/adapter.rs deleted file mode 100644 index f606829f..00000000 --- a/core/src/parser/adapter.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod orthographical_variant_adapter; diff --git a/core/src/parser/adapter/orthographical_variant_adapter.rs b/core/src/parser/adapter/orthographical_variant_adapter.rs deleted file mode 100644 index 9d081f3b..00000000 --- a/core/src/parser/adapter/orthographical_variant_adapter.rs +++ /dev/null @@ -1,114 +0,0 @@ -use itertools::Itertools; - -pub type Variant = &'static [&'static str]; - -pub trait OrthographicalVariants { - const の: Variant; - const ツ: Variant; - const ケ: Variant; - const 薮: Variant; - const 崎: Variant; - const 檜: Variant; - const 龍: Variant; - const 竈: Variant; - const 嶋: Variant; - const 舘: Variant; - const 脊: Variant; - const 渕: Variant; - const 己: Variant; - const 槇: Variant; - const 治: Variant; - const 佛: Variant; - const 澤: Variant; - const 塚: Variant; - const 恵: Variant; - const 穂: Variant; - const 梼: Variant; - const 蛍: Variant; - const 與: Variant; - const 瀧: Variant; - const 籠: Variant; - const 濱: Variant; - const 祗: Variant; - const 曾: Variant; -} - -impl OrthographicalVariants for Variant { - const の: Variant = &["の", "ノ", "之"]; - const ツ: Variant = &["ツ", "ッ"]; - const ケ: Variant = &["ケ", "ヶ", "が", "ガ"]; - const 薮: Variant = &["薮", "藪", "籔"]; - const 崎: Variant = &["崎", "﨑"]; - const 檜: Variant = &["桧", "檜"]; - const 龍: Variant = &["龍", "竜"]; - const 竈: Variant = &["竈", "竃", "釜"]; - const 嶋: Variant = &["嶋", "島"]; - const 舘: Variant = &["舘", "館"]; - const 脊: Variant = &["脊", "背"]; - const 渕: Variant = &["渕", "淵"]; - const 己: Variant = &["己", "巳"]; - const 槇: Variant = &["槇", "槙"]; - const 治: Variant = &["治", "冶"]; - const 佛: Variant = &["佛", "仏"]; - const 澤: Variant = &["澤", "沢"]; - const 塚: Variant = &["塚", "塚"]; - const 恵: Variant = &["恵", "惠"]; - const 穂: Variant = &["穂", "穗"]; - const 梼: Variant = &["梼", "檮"]; - const 蛍: Variant = &["蛍", "螢"]; - const 與: Variant = &["與", "与"]; - const 瀧: Variant = &["瀧", "滝"]; - const 籠: Variant = &["籠", "篭"]; - const 濱: Variant = &["濱", "浜"]; - const 祗: Variant = &["祗", "祇"]; - const 曾: Variant = &["曾", "曽"]; -} - -pub struct OrthographicalVariantAdapter { - pub variant_list: Vec, -} - -impl OrthographicalVariantAdapter { - pub fn apply(self, input: &str, region_name: &str) -> Option<(String, String)> { - // 必要なパターンのみを選別する - let variant_list: Vec<&Variant> = self - .variant_list - .iter() - .filter(|v| v.iter().any(|c| input.contains(c))) - .collect(); - if variant_list.is_empty() { - return None; - } - - // マッチ候補を容れておくためのVector - let mut candidates: Vec = vec![region_name.to_string()]; - // パターンを一つづつ検証していく - for variant in variant_list { - let mut semi_candidates: Vec = vec![]; - // variantから順列を作成 - // ["ケ", "ヶ", "が"] -> (ケ, ヶ), (ケ, が), (ヶ, ケ), (ヶ, が), (が, ケ), (が, ヶ) - for permutation in variant.iter().permutations(2) { - for candidate in candidates.iter().filter(|c| c.contains(permutation[0])) { - // マッチ候補の中でパターンに引っかかるものがあれば文字を置き換えてマッチを試す - let edited_region_name = candidate.replace(permutation[0], permutation[1]); - if input.starts_with(&edited_region_name) { - // マッチすれば早期リターン - return Some(( - region_name.to_string(), - input - .chars() - .skip(edited_region_name.chars().count()) - .collect(), - )); - } else { - // マッチしなければsemi_candidatesに置き換え後の文字列をpush - semi_candidates.push(edited_region_name); - }; - } - } - candidates = semi_candidates; - candidates.push(region_name.to_string()); - } - None - } -} diff --git a/core/src/repository/geolonia.rs b/core/src/repository/geolonia.rs index 5a4724a4..bd72317e 100644 --- a/core/src/repository/geolonia.rs +++ b/core/src/repository/geolonia.rs @@ -1,6 +1,2 @@ pub(crate) mod city; -#[deprecated(since = "0.1.23", note = "This module will be deleted in v0.2")] -pub mod city_master_api; pub(crate) mod prefecture; -#[deprecated(since = "0.1.23", note = "This module will be deleted in v0.2")] -pub mod prefecture_master_api; diff --git a/core/src/repository/geolonia/city_master_api.rs b/core/src/repository/geolonia/city_master_api.rs deleted file mode 100644 index b00eff84..00000000 --- a/core/src/repository/geolonia/city_master_api.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::domain::geolonia::entity::{City, Town}; -use crate::domain::geolonia::error::Error; -use crate::service::geolonia::GeoloniaApiService; - -pub struct CityMasterApi { - pub server_url: &'static str, -} - -impl Default for CityMasterApi { - fn default() -> Self { - Self { - server_url: "https://geolonia.github.io/japanese-addresses/api/ja", - } - } -} - -impl CityMasterApi { - pub async fn get(&self, prefecture_name: &str, city_name: &str) -> Result { - let endpoint = format!("{}/{}/{}.json", self.server_url, prefecture_name, city_name); - let api_service = GeoloniaApiService {}; - let towns = api_service.get::>(&endpoint).await?; - Ok(City { - name: city_name.to_string(), - towns, - }) - } - #[cfg(feature = "blocking")] - pub fn get_blocking(&self, prefecture_name: &str, city_name: &str) -> Result { - let endpoint = format!("{}/{}/{}.json", self.server_url, prefecture_name, city_name); - let api_service = GeoloniaApiService {}; - let towns = api_service.get_blocking::>(&endpoint)?; - Ok(City { - name: city_name.to_string(), - towns, - }) - } -} - -#[cfg(all(test, not(feature = "blocking")))] -mod tests { - use crate::domain::geolonia::entity::Town; - - use crate::repository::geolonia::city_master_api::CityMasterApi; - - #[tokio::test] - async fn 非同期_石川県羽咋郡志賀町_成功() { - let city_master_api: CityMasterApi = Default::default(); - let result = city_master_api.get("石川県", "羽咋郡志賀町").await; - let city = result.unwrap(); - assert_eq!(city.name, "羽咋郡志賀町"); - let town = Town { - name: "末吉".to_string(), - koaza: "千古".to_string(), - lat: Some(37.006235), - lng: Some(136.779155), - }; - assert!(city.towns.contains(&town)); - } - - #[tokio::test] - async fn 非同期_誤った市区町村名_失敗() { - let city_master_api: CityMasterApi = Default::default(); - let result = city_master_api.get("石川県", "敦賀市").await; - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().error_message, - format!( - "{}/石川県/敦賀市.jsonを取得できませんでした", - city_master_api.server_url - ) - ); - } -} - -#[cfg(all(test, feature = "blocking"))] -mod blocking_tests { - use crate::domain::geolonia::entity::Town; - use crate::repository::geolonia::city_master_api::CityMasterApi; - - #[test] - fn 同期_石川県羽咋郡志賀町_成功() { - let city_master_api: CityMasterApi = Default::default(); - let result = city_master_api.get_blocking("石川県", "羽咋郡志賀町"); - let city = result.unwrap(); - assert_eq!(city.name, "羽咋郡志賀町"); - let town = Town { - name: "末吉".to_string(), - koaza: "千古".to_string(), - lat: Some(37.006235), - lng: Some(136.779155), - }; - assert!(city.towns.contains(&town)); - } - - #[test] - fn 同期_誤った市区町村名_失敗() { - let city_master_api: CityMasterApi = Default::default(); - let result = city_master_api.get_blocking("石川県", "敦賀市"); - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().error_message, - format!( - "{}/石川県/敦賀市.jsonを取得できませんでした", - city_master_api.server_url - ) - ); - } -} diff --git a/core/src/repository/geolonia/prefecture.rs b/core/src/repository/geolonia/prefecture.rs index 9681c587..3e89489c 100644 --- a/core/src/repository/geolonia/prefecture.rs +++ b/core/src/repository/geolonia/prefecture.rs @@ -28,7 +28,6 @@ impl PrefectureMasterRepository { #[cfg(all(test, not(feature = "blocking")))] mod tests { use crate::repository::geolonia::prefecture::PrefectureMasterRepository; - use crate::repository::geolonia::prefecture_master_api::PrefectureMasterApi; use crate::service::geolonia::GeoloniaApiService; #[tokio::test] @@ -61,15 +60,12 @@ mod tests { #[tokio::test] async fn 非同期_誤った都道府県名_失敗() { - let prefecture_master_api: PrefectureMasterApi = Default::default(); - let result = prefecture_master_api.get("大阪都").await; + let api_service = GeoloniaApiService {}; + let result = PrefectureMasterRepository::get(&api_service, "大阪都").await; assert!(result.is_err()); assert_eq!( result.err().unwrap().error_message, - format!( - "{}/大阪都/master.jsonを取得できませんでした", - prefecture_master_api.server_url - ) + "https://yuukitoriyama.github.io/geolonia-japanese-addresses-accompanist/大阪都/master.jsonを取得できませんでした", ); } } diff --git a/core/src/repository/geolonia/prefecture_master_api.rs b/core/src/repository/geolonia/prefecture_master_api.rs deleted file mode 100644 index b98d0929..00000000 --- a/core/src/repository/geolonia/prefecture_master_api.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::domain::geolonia::entity::Prefecture; -use crate::domain::geolonia::error::Error; -use crate::service::geolonia::GeoloniaApiService; - -pub struct PrefectureMasterApi { - pub server_url: &'static str, -} - -impl Default for PrefectureMasterApi { - fn default() -> Self { - Self { - server_url: "https://yuukitoriyama.github.io/geolonia-japanese-addresses-accompanist", - } - } -} - -impl PrefectureMasterApi { - pub async fn get(&self, prefecture_name: &str) -> Result { - let endpoint = format!("{}/{}/master.json", self.server_url, prefecture_name); - let api_service = GeoloniaApiService {}; - api_service.get::(&endpoint).await - } - #[cfg(feature = "blocking")] - pub fn get_blocking(&self, prefecture_name: &str) -> Result { - let endpoint = format!("{}/{}/master.json", self.server_url, prefecture_name); - let api_service = GeoloniaApiService {}; - api_service.get_blocking::(&endpoint) - } -} - -#[cfg(all(test, not(feature = "blocking")))] -mod tests { - use crate::repository::geolonia::prefecture_master_api::PrefectureMasterApi; - - #[tokio::test] - async fn 非同期_富山県_成功() { - let prefecture_master_api: PrefectureMasterApi = Default::default(); - let result = prefecture_master_api.get("富山県").await; - let prefecture = result.unwrap(); - assert_eq!(prefecture.name, "富山県"); - let cities = vec![ - "富山市", - "高岡市", - "魚津市", - "氷見市", - "滑川市", - "黒部市", - "砺波市", - "小矢部市", - "南砺市", - "射水市", - "中新川郡舟橋村", - "中新川郡上市町", - "中新川郡立山町", - "下新川郡入善町", - "下新川郡朝日町", - ]; - for city in cities { - assert!(prefecture.cities.contains(&city.to_string())); - } - } - - #[tokio::test] - async fn 非同期_誤った都道府県名_失敗() { - let prefecture_master_api: PrefectureMasterApi = Default::default(); - let result = prefecture_master_api.get("大阪都").await; - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().error_message, - format!( - "{}/大阪都/master.jsonを取得できませんでした", - prefecture_master_api.server_url - ) - ); - } -} - -#[cfg(all(test, feature = "blocking"))] -mod blocking_tests { - use crate::repository::geolonia::prefecture_master_api::PrefectureMasterApi; - - #[test] - fn 同期_富山県_成功() { - let prefecture_master_api: PrefectureMasterApi = Default::default(); - let result = prefecture_master_api.get_blocking("富山県"); - let prefecture = result.unwrap(); - assert_eq!(prefecture.name, "富山県"); - let cities = vec![ - "富山市", - "高岡市", - "魚津市", - "氷見市", - "滑川市", - "黒部市", - "砺波市", - "小矢部市", - "南砺市", - "射水市", - "中新川郡舟橋村", - "中新川郡上市町", - "中新川郡立山町", - "下新川郡入善町", - "下新川郡朝日町", - ]; - for city in cities { - assert!(prefecture.cities.contains(&city.to_string())); - } - } - - #[test] - fn 同期_誤った都道府県名_失敗() { - let prefecture_master_api: PrefectureMasterApi = Default::default(); - let result = prefecture_master_api.get_blocking("大阪都"); - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().error_message, - format!( - "{}/大阪都/master.jsonを取得できませんでした", - prefecture_master_api.server_url - ) - ); - } -} diff --git a/core/src/tokenizer/read_city.rs b/core/src/tokenizer/read_city.rs index 0233f777..048e1a7b 100644 --- a/core/src/tokenizer/read_city.rs +++ b/core/src/tokenizer/read_city.rs @@ -33,6 +33,7 @@ impl Tokenizer { match self.get_prefecture_name() { Some("青森県") => { variant_list.push(OrthographicalVariant::舘); + variant_list.push(OrthographicalVariant::鰺); } Some("宮城県") => { variant_list.push(OrthographicalVariant::竈); @@ -53,6 +54,9 @@ impl Tokenizer { Some("福岡県") => { variant_list.push(OrthographicalVariant::恵); } + Some("長崎県") => { + variant_list.push(OrthographicalVariant::諫); + } _ => {} } for candidate in candidates { diff --git a/core/src/tokenizer/read_town.rs b/core/src/tokenizer/read_town.rs index 7474f747..cab113fa 100644 --- a/core/src/tokenizer/read_town.rs +++ b/core/src/tokenizer/read_town.rs @@ -73,6 +73,7 @@ fn find_town(input: &str, candidates: &Vec) -> Option<(String, String)> OrthographicalVariant::檜, OrthographicalVariant::竈, OrthographicalVariant::舘, + OrthographicalVariant::鰺, OrthographicalVariant::脊, OrthographicalVariant::渕, OrthographicalVariant::己, @@ -90,6 +91,13 @@ fn find_town(input: &str, candidates: &Vec) -> Option<(String, String)> OrthographicalVariant::濱, OrthographicalVariant::祗, OrthographicalVariant::曾, + OrthographicalVariant::國, + OrthographicalVariant::鉋, + OrthographicalVariant::鷆, + OrthographicalVariant::斑, + OrthographicalVariant::櫻, + OrthographicalVariant::櫟, + OrthographicalVariant::冨, ], }; if let Some(result) = adapter.apply(input, candidate) { diff --git a/python/Cargo.toml b/python/Cargo.toml index 9c38f501..5b435843 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -17,4 +17,4 @@ crate-type = ["cdylib"] [dependencies] japanese-address-parser = { path = "../core", features = ["blocking"] } -pyo3 = { version = "0.22.0", features = ["abi3-py37"] } +pyo3 = { version = "0.23.2", features = ["abi3-py37"] } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 3a572731..65503637 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -10,7 +10,7 @@ name = "integration_tests" path = "integration_tests.rs" [dev-dependencies] -csv = "1.3.0" +csv = "1.3.1" japanese-address-parser = { path = "../core" } -serde = { version = "1.0.197", features = ["derive"] } +serde.workspace = true tokio.workspace = true diff --git "a/tests/test_data/\345\270\202\345\214\272\347\224\272\346\235\221\345\220\215\343\203\254\343\203\231\343\203\253\343\201\247\343\201\256\350\241\250\350\250\230\343\202\206\343\202\214.csv" "b/tests/test_data/\345\270\202\345\214\272\347\224\272\346\235\221\345\220\215\343\203\254\343\203\231\343\203\253\343\201\247\343\201\256\350\241\250\350\250\230\343\202\206\343\202\214.csv" index 5b526087..2c3c81d4 100644 --- "a/tests/test_data/\345\270\202\345\214\272\347\224\272\346\235\221\345\220\215\343\203\254\343\203\231\343\203\253\343\201\247\343\201\256\350\241\250\350\250\230\343\202\206\343\202\214.csv" +++ "b/tests/test_data/\345\270\202\345\214\272\347\224\272\346\235\221\345\220\215\343\203\254\343\203\231\343\203\253\343\201\247\343\201\256\350\241\250\350\250\230\343\202\206\343\202\214.csv" @@ -1,4 +1,7 @@ address,prefecture,city,town,rest +# 青森県 +青森県西津軽郡鰺ヶ沢町大字舞戸町字鳴戸321番地,青森県,西津軽郡鰺ヶ沢町,大字舞戸町,字鳴戸321番地 +青森県西津軽郡鯵ヶ沢町大字舞戸町字鳴戸321番地,青森県,西津軽郡鰺ヶ沢町,大字舞戸町,字鳴戸321番地 # 宮城県 宮城県塩竈市海岸通15-1,宮城県,塩竈市,海岸通,15-1 宮城県塩釜市海岸通15-1,宮城県,塩竈市,海岸通,15-1 @@ -10,3 +13,6 @@ address,prefecture,city,town,rest 兵庫県宝塚市売布東の町8-19,兵庫県,宝塚市,売布東の町,8-19 兵庫県宝塚市武庫川町1-1,兵庫県,宝塚市,武庫川町,1-1 兵庫県宝塚市武庫川町1-1,兵庫県,宝塚市,武庫川町,1-1 +# 長崎県 +長崎県諫早市東小路町7-1,長崎県,諫早市,東小路町,7-1 +長崎県諌早市東小路町7-1,長崎県,諫早市,東小路町,7-1 diff --git "a/tests/test_data/\347\225\260\345\255\227\344\275\223\343\201\247\343\201\257\343\201\252\343\201\204\350\241\250\350\250\230\343\202\206\343\202\214\343\201\270\343\201\256\345\257\276\345\277\234.csv" "b/tests/test_data/\347\225\260\345\255\227\344\275\223\343\201\247\343\201\257\343\201\252\343\201\204\350\241\250\350\250\230\343\202\206\343\202\214\343\201\270\343\201\256\345\257\276\345\277\234.csv" index 4c1b0914..f76a6bd8 100644 --- "a/tests/test_data/\347\225\260\345\255\227\344\275\223\343\201\247\343\201\257\343\201\252\343\201\204\350\241\250\350\250\230\343\202\206\343\202\214\343\201\270\343\201\256\345\257\276\345\277\234.csv" +++ "b/tests/test_data/\347\225\260\345\255\227\344\275\223\343\201\247\343\201\257\343\201\252\343\201\204\350\241\250\350\250\230\343\202\206\343\202\214\343\201\270\343\201\256\345\257\276\345\277\234.csv" @@ -3,3 +3,12 @@ address,prefecture,city,town,rest 神奈川県鎌倉市山ノ内189,神奈川県,鎌倉市,山ノ内,189 神奈川県鎌倉市山の内189,神奈川県,鎌倉市,山ノ内,189 神奈川県鎌倉市山之内189,神奈川県,鎌倉市,山ノ内,189 +# 「上氷鉋」と「上氷飽」の表記揺れへの対応 +長野県長野市川中島町上氷鉋1368,長野県,長野市,川中島町上氷鉋,1368 +長野県長野市川中島町上氷飽1368,長野県,長野市,川中島町上氷鉋,1368 +# 「斑目」と「班目」の表記揺れへの対応 +神奈川県南足柄市班目639,神奈川県,南足柄市,班目,639 +神奈川県南足柄市斑目639,神奈川県,南足柄市,班目,639 +# 「櫟」と「擽」の表記ゆれへの対応 +兵庫県南あわじ市松帆櫟田196,兵庫県,南あわじ市,松帆櫟田,196 +兵庫県南あわじ市松帆擽田196,兵庫県,南あわじ市,松帆櫟田,196 diff --git "a/tests/test_data/\347\225\260\345\255\227\344\275\223\346\227\247\345\255\227\344\275\223\343\201\270\343\201\256\345\257\276\345\277\234.csv" "b/tests/test_data/\347\225\260\345\255\227\344\275\223\346\227\247\345\255\227\344\275\223\343\201\270\343\201\256\345\257\276\345\277\234.csv" index 8afeb572..6ca27f7f 100644 --- "a/tests/test_data/\347\225\260\345\255\227\344\275\223\346\227\247\345\255\227\344\275\223\343\201\270\343\201\256\345\257\276\345\277\234.csv" +++ "b/tests/test_data/\347\225\260\345\255\227\344\275\223\346\227\247\345\255\227\344\275\223\343\201\270\343\201\256\345\257\276\345\277\234.csv" @@ -84,3 +84,18 @@ address,prefecture,city,town,rest # 「小曾根」と「小曽根」の表記ゆれへの対応 埼玉県熊谷市小曽根1220,埼玉県,熊谷市,小曽根,1220 埼玉県熊谷市小曾根1220,埼玉県,熊谷市,小曽根,1220 +# 「神代國衙」と「神代国衙」の表記揺れへの対応 +兵庫県南あわじ市神代國衙1680,兵庫県,南あわじ市,神代國衙,1680 +兵庫県南あわじ市神代国衙1680,兵庫県,南あわじ市,神代國衙,1680 +# 「鷏和」と「鷆和」の表記揺れへの対応 +兵庫県赤穂市鷏和422,兵庫県,赤穂市,鷏和,422 +兵庫県赤穂市鷆和422,兵庫県,赤穂市,鷏和,422 +# 「南桜」と「南櫻」の表記揺れへの対応 +滋賀県野洲市南桜1792,滋賀県,野洲市,南櫻,1792 +滋賀県野洲市南櫻1792,滋賀県,野洲市,南櫻,1792 +# 「富」と「冨」の表記ゆれへの対応 +兵庫県神崎郡神河町吉冨88番地10号,兵庫県,神崎郡神河町,吉冨,88番地10号 +兵庫県神崎郡神河町吉富88番地10号,兵庫県,神崎郡神河町,吉冨,88番地10号 +# 「鰺」と「鯵」の表記ゆれへの対応 +新潟県新潟市南区鯵潟423,新潟県,新潟市南区,鯵潟,423 +新潟県新潟市南区鰺潟423,新潟県,新潟市南区,鯵潟,423 diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 59db0218..2372d2da 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -27,7 +27,7 @@ nightly = [ [dependencies] console_error_panic_hook = "0.1.7" japanese-address-parser = { path = "../core" } -serde-wasm-bindgen = "0.6.1" +serde-wasm-bindgen = "0.6.5" wasm-bindgen = { workspace = true } wasm-bindgen-futures = { workspace = true } # 以下は`nightly`が有効な場合のみ使用される diff --git a/wasm/LICENSE b/wasm/LICENSE index 09fdfd2d..2c98bacc 100644 --- a/wasm/LICENSE +++ b/wasm/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 ToriChan +Copyright (c) 2023-2024 Yuuki Toriyama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/wasm/README.md b/wasm/README.md index b1d1c954..6c17ceb2 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -11,13 +11,13 @@ A Library for processing addresses of Japan written in Rust. Install with npm: ```bash -npm install @toriyama/japanese-address-parser +npm install @toriyama/japanese-address-parser@0.2 ``` Install with yarn: ```bash -yarn add @toriyama/japanese-address-parser +yarn add @toriyama/japanese-address-parser@0.2 ``` ## Introduction diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 5054d856..365e5ece 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -5,6 +5,14 @@ use japanese_address_parser::parser; use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; +#[wasm_bindgen(start)] +fn start() { + #[cfg(feature = "debug")] + console_error_panic_hook::set_once(); + #[cfg(feature = "nightly")] + console_log::init_with_level(log::Level::Trace).expect("could not initialize log"); +} + #[wasm_bindgen(typescript_custom_section)] const TYPESCRIPT_TYPE: &'static str = r#" export interface ParseResult { @@ -41,8 +49,6 @@ pub struct Parser { impl Parser { #[wasm_bindgen(constructor)] pub fn new() -> Self { - #[cfg(feature = "debug")] - console_error_panic_hook::set_once(); Parser { parser: parser::Parser::default(), } diff --git a/wasm/src/nightly.rs b/wasm/src/nightly.rs index bbe07dea..4e6e868d 100644 --- a/wasm/src/nightly.rs +++ b/wasm/src/nightly.rs @@ -30,11 +30,6 @@ export interface ParsedAddress { metadata: Metadata; }"#; -#[wasm_bindgen(start)] -fn start() { - console_log::init_with_level(log::Level::Trace).expect("could not initialize log"); -} - #[derive(Deserialize)] pub struct Options { #[serde(alias = "dataSource")]