| Crates.io | runmunch |
| lib.rs | runmunch |
| version | 1.1.0 |
| created_at | 2025-11-23 20:19:23.581648+00 |
| updated_at | 2025-11-24 05:12:59.632367+00 |
| description | A Rust implementation of hunspell's unmunch tool for expanding dictionary words using affix files |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1946950 |
| size | 83,711 |
A fast, efficient Rust implementation of hunspell's unmunch tool for expanding dictionary words using morphological affix rules. Generate all possible word forms from dictionaries or expand individual words interactively.
--expand mode)--find-base mode)cargo install runmunch
Or build from source:
git clone <repository>
cd runmunch
cargo build --release
runmunch affix_file.aff dictionary_file.dic
Example:
runmunch hr_HR.aff hr_HR.dic > expanded_words.txt
-e/--expand mode):Without dictionary (tries all possible rules):
echo -e "word1\nword2\nword3" | runmunch -e affix_file.aff
# or
echo -e "word1\nword2\nword3" | runmunch --expand affix_file.aff
With dictionary (uses word-specific flags for better results):
echo -e "word1\nword2\nword3" | runmunch -e affix_file.aff dictionary_file.dic
# or
echo -e "word1\nword2\nword3" | runmunch --expand affix_file.aff dictionary_file.dic
-b/--find-base mode):Find base forms from inflected words and expand them (requires dictionary):
echo -e "cats\nwalked\nbooks" | runmunch -e -b affix_file.aff dictionary_file.dic
# or
echo -e "cats\nwalked\nbooks" | runmunch --expand --find-base affix_file.aff dictionary_file.dic
This mode:
Examples:
# German words - expand base forms
echo -e "Haus\nAuto\nKind" | runmunch -e de.aff de.dic
# Croatian words - expand base forms
echo -e "kuća\nkava\ngrad" | runmunch -e hr_HR.aff hr_HR.dic
# English inflected forms - find base and expand
echo -e "cats\nwalked\nbooks" | runmunch -e -b en.aff en.dic
use runmunch::{Runmunch, WordExpander, AffixFile};
// Create a new Runmunch instance
let mut runmunch = Runmunch::new();
// Load affix and dictionary files
runmunch.load_affix_file("path/to/file.aff")?;
runmunch.load_dictionary("path/to/file.dic")?;
// Expand all words from the dictionary
let expanded_words = runmunch.unmunch()?;
for word in expanded_words {
println!("{}", word);
}
// Or expand specific words
let word_forms = runmunch.expand_word("example")?;
for form in word_forms {
println!("{}", form);
}
// Find base word and expand it
let expanded_forms = runmunch.find_base_and_expand("examples")?;
for form in expanded_forms {
println!("{}", form);
}
use runmunch::{WordExpander, AffixFile};
// Load affix file
let affix_file = AffixFile::load("path/to/file.aff")?;
// Create expander and set affix file
let mut expander = WordExpander::new();
expander.set_affix_file(&affix_file);
// Expand a word with specific flags
let expanded = expander.expand_with_flags("work", &["ED".to_string()])?;
// Results might include: ["work", "worked"]
// Find base word from inflected form
let base_words = expander.find_base_word("worked", &dictionary)?;
// Results might include: ["work"]
// Find base and expand
let all_forms = expander.find_base_and_expand("worked", &dictionary)?;
// Results might include: ["work", "worked", ...]
Runmunch supports hunspell affix file format with features like:
PFX)SFX)FLAG long)Example affix file:
FLAG long
PFX UN Y 1
PFX UN 0 un .
SFX ED Y 1
SFX ED 0 ed .
SFX S Y 1
SFX S 0 s .
Standard hunspell dictionary format:
3
hello/ED
world
test/UN,S
/# Create a simple affix file
cat > simple.aff << EOF
PFX UN Y 1
PFX UN 0 un .
SFX ED Y 1
SFX ED 0 ed .
EOF
# Test expansion
echo "happy" | runmunch --expand simple.aff
# Output: happy, unhappy
# Expand Croatian words
echo -e "kuća\nčitati" | runmunch --expand hunspell-hr/hr_HR.aff
# Unmunch Croatian dictionary
runmunch hunspell-hr/hr_HR.aff hunspell-hr/hr_HR.dic | wc -l
# Shows total expanded words
Runmunch delivers excellent performance across different languages and use cases:
| Language | Input Words | Output Words | Time | Speed | Expansion Ratio |
|---|---|---|---|---|---|
| German | 75,888 | 1,226,445 | 3.23s | 23,493 w/s | 16.16x |
| Croatian | 53,712 | 28,428,780 | 52.63s | 1,020 w/s | 529.28x |
--expand mode)| Mode | Language | Input | Output | Time | Speed |
|---|---|---|---|---|---|
| No Dict | German | 10 words | 528 forms | 0.023s | 435 w/s |
| No Dict | Croatian | 10 words | 2,015 forms | 0.027s | 370 w/s |
| With Dict | German | 10 words | 236 forms | 0.073s | 137 w/s |
| With Dict | Croatian | 10 words | 1,515 forms | 0.081s | 123 w/s |
FLAG long), and flag aliases (AF directive)The main components of the library:
RunmunchThe main interface combining affix files and dictionaries.
WordExpanderCore word expansion logic using affix rules.
AffixFileParser and representation of hunspell affix files.
DictionaryParser and representation of hunspell dictionary files.
Runmunch uses comprehensive error handling with descriptive error messages:
use runmunch::RunmunchError;
match runmunch.load_affix_file("invalid.aff") {
Ok(_) => println!("Success!"),
Err(RunmunchError::Io(e)) => eprintln!("IO error: {}", e),
Err(RunmunchError::InvalidAffix(msg)) => eprintln!("Invalid affix: {}", msg),
Err(e) => eprintln!("Other error: {}", e),
}
Contributions are welcome! Please feel free to:
Licensed under MIT OR Apache-2.0.