mòine
mòine is a Python and Rust library for romanization-aware string comparison.
It implements Lattice Path Edit Distance (LPED; Kaji, 2023), a distance metric that compares strings through possible reading paths rather than only through visible surface characters.
This is useful when romanized input and written Japanese or Chinese look far apart as strings, but stay close in reading space.
With the package installed and language artifacts downloaded:
>>>
>>>
2
>>>
0
>>>
0
>>>
0
Name
The project name comes from Moine, a peated malt from Bunnahabhain and one of
the developer's favorite Scotch whiskies. In Japanese, the name has several
plausible katakana renderings, such as モイニャ, モーイン, and モアンヌ, which
makes it a fitting name for a project about readings, spelling variation, and
ambiguity in input sequences.
Features
- Japanese comparison with UniDic-CWJ-derived reading artifacts and separate SudachiDict-derived artifacts.
- Chinese comparison with CC-CEDICT-derived no-tone pinyin artifacts.
- Plain string Levenshtein-compatible distance helpers.
- Lattice-aware Damerau-Levenshtein distance for adjacent transpositions.
- Combined
min(surface Damerau-Levenshtein, LPED)scorer for candidate reranking. - Normalized similarity /
ratiohelpers in0.0..=1.0. - RapidFuzz-inspired APIs such as
cdistand partial matching helpers.
Installation
Install the Python package:
Install the Rust command-line tool:
The packages do not bundle dictionary data. Download the language artifacts you need explicitly:
# Default Japanese artifact: UniDic-CWJ
# Explicit Japanese sources
# Chinese artifact: CC-CEDICT
# Same selectors are available from the Rust CLI.
ja is the short default selector for the current Japanese artifact, which is
UniDic-CWJ. Use ja-unidic or ja-sudachi when the dictionary source should be
explicit.
Quick Start
Use the top-level Python API when you want mòine to load the default dictionary for a language:
# 0
# 0.7142857142857143
# 1.0
# 0
Load a dictionary explicitly when you want to control startup cost or artifact location:
=
# 0
Use cdist for query-by-choice matrices:
=
For search or entity matching, generate candidates with your existing system and use mòine as a reading-aware reranker:
=
=
=
=
# [('モイニャ', 2), ('モーイン', 2), ('モアンヌ', 3), ('ストイーシャ', 7)]
Score interpretation is intentionally simple: distance=0 means the best
reading paths are identical, combined_distance is the minimum of surface
Damerau-Levenshtein and LPED, distance metrics are smaller-is-better, ratio
and normalized_similarity are in 0.0..=1.0 and larger-is-better, and
score_cutoff filters in the RapidFuzz style.
Command Line
Most users only need the public runtime commands:
Use moine download ja-unidic for explicit UniDic-CWJ and
moine download ja-sudachi for SudachiDict-full.
The artifact bundle, verification, archive, and raw-dictionary inspection commands are maintainer-facing tools for producing and checking release assets. They are documented in docs/development.md and docs/release_process.md.
The public comparison commands can also emit lattice graphs:
moine compare --romaji-lattice <PATH> --output-format <dot|svg|png> for
Japanese romaji lattices, and
moine chinese-compare --pinyin-lattice <PATH> --output-format <dot|svg|png>
for Chinese pinyin lattices. Writing SVG or PNG graphs requires the Graphviz
dot command to be available in PATH; DOT output does not require that runtime
dependency. See CLI usage for rendered
examples.
Documentation
- Project documentation
- Installation
- Python usage
- CLI usage
- API reference
- Rust usage
- Dictionary artifacts
- Browser demo
- Rust docs
Developer and maintainer notes live under docs/, starting with docs/development.md and docs/release_process.md. See CONTRIBUTING.md before opening pull requests.
How It Differs From RapidFuzz
RapidFuzz is the better fit when both inputs should be compared directly as surface strings and you need a broad set of highly optimized fuzzy-matching scorers. mòine focuses on a narrower problem: comparing strings through possible reading paths before edit distance is computed.
Benchmark
Recorded on 2026-06-20. The first table reports scoring time only; dictionary loading is shown separately below.
[!IMPORTANT] RapidFuzz measures surface Levenshtein distance, so it is expected to be much faster. Treat this as a reference for mòine's dictionary-backed reading edit distance, not a same-task speed comparison.
This is a quick local benchmark command. The release-wheel command used for the recorded table lives in development notes.
| Method | mean (±std) | relative |
|---|---|---|
| RapidFuzz Levenshtein | 0.15 ± 0.01 us/call | 1.00x |
| mòine ja distance | 58.38 ± 109.10 us/call | 390x |
Fresh dictionary loads from the standard installed artifacts, measured over 100 loads:
| Dictionary | mean (±std) |
|---|---|
| UniDic-CWJ | 475.23 ms ± 22.41 ms |
| SudachiDict-full | 1959.09 ms ± 43.83 ms |
| CC-CEDICT | 168.82 ms ± 12.47 ms |
Limitations
- mòine does not reproduce the original paper's private search-query-log evaluation.
- Dictionary-backed comparison requires separately distributed dictionary artifacts.
- UniDic matching intentionally does not use MeCab/Viterbi costs.
- Chinese support is Mandarin pinyin only; it does not model Cantonese/Jyutping or non-Mandarin readings.
processor,score_hint, NumPy dtype options, and worker parallelism are not part of the currentcdistAPI.
Reference
[!CAUTION] This project is not the official implementation by the paper author.
License
mòine source code is licensed under either MIT or Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.
Dictionary data is separate. UniDic-derived, SudachiDict-derived, and CC-CEDICT-derived artifacts carry their own license and attribution metadata, and should keep dictionary license information separate from the mòine source-code license. See THIRD_PARTY_NOTICES.md.