Metadata-Version: 2.4
Name: textstat-rs
Version: 1.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Text Processing :: Linguistic
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Requires-Dist: datasets==3.6.0 ; extra == 'dev'
Requires-Dist: pytest>=8.3.5 ; extra == 'dev'
Requires-Dist: textstat>=0.7.13 ; extra == 'dev'
Requires-Dist: nltk ; extra == 'dev'
Requires-Dist: maturin ; extra == 'dev'
Requires-Dist: mypy ; extra == 'dev'
Provides-Extra: dev
License-File: LICENSE
Summary: Rust port of the textstat textual analysis library, with Python bindings.
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/CZboop/textstat-rs
Project-URL: Issues, https://github.com/CZboop/textstat-rs/issues
Project-URL: Repository, https://github.com/CZboop/textstat-rs

# Textstat-rs
Rust port of the textstat textual analysis library, with Python bindings.
Drop-in replacements for 11 key metrics in US English.

**99.98% exact output match, with at least 2.4x-7x speedup, with 2 most sped-up metrics at ~14x and ~79x** based on benchmarking scripts included in repo, running on Wikipedia dataset as a varied, modern text corpus.

## Installation

```bash
pip install textstat-rs
```

Pre-release versions need `pip install --pre textstat-rs`.

Requires Python 3.10+. Wheels are built for Linux (x86_64, x86, aarch64, armv7; glibc and musl), macOS (x86_64, arm64) and Windows (x64, arm64). They are `abi3` wheels, so one wheel per platform covers every supported Python version. On other platforms pip falls back to the sdist, which needs a Rust toolchain to build.

## Usage

Import name is `textstat_rs`; every metric takes the text as its first argument.

```python
import textstat_rs

text = "The cat sat on the mat. It was a sunny day."

textstat_rs.flesch_reading_ease(text)   # 108.96159090909092
textstat_rs.flesch_kincaid_grade(text)  # -0.5722727272727273
textstat_rs.text_standard(text)         # '0th and 1st grade'
```

The exposed metrics match `textstat`'s signatures, so an existing import can be swapped in place:

```python
import textstat_rs as textstat
```

Optional arguments are the same as the Python library, other than the exceptions noted below:

```python
textstat_rs.gunning_fog(text, syllable_threshold=3)
textstat_rs.linsear_write_formula(text, strict_lower=False, strict_upper=True)
textstat_rs.reading_time(text, ms_per_char=14.69)
```

The counting helpers the formulas are built on are exposed too: `syllable_count`, `sentence_count`, `lexicon_count`, `char_count`, `letter_count`, `polysyllabcount`, `miniword_count` and `difficult_words`.

## Python Comparison

### Functions
#### Exposed Metrics

| Python function                   | Exposed? | Notes                                                      |
| --------------------------------- | :------: | ---------------------------------------------------------- |
| `flesch_reading_ease`             |    ✅     |                                                            |
| `flesch_kincaid_grade`            |    ✅     |                                                            |
| `smog_index`                      |    ✅     |                                                            |
| `coleman_liau_index`              |    ✅     |                                                            |
| `automated_readability_index`     |    ✅     |                                                            |
| `dale_chall_readability_score`    |    ✅     |                                                            |
| `linsear_write_formula`           |    ✅     | signature parity (`strict_lower`, `strict_upper`)          |
| `gunning_fog`                     |    ✅     | Rust exposes `syllable_threshold` arg, Python hardcodes it |
| `spache_readability`              |    ✅     | Rust missing `float_output` arg                            |
| `text_standard`                   |    ✅     | Rust missing `float_output` arg, returns `String` only     |
| `reading_time`                    |    ✅     |                                                            |
| `mcalpine_eflaw`                  |    ✅     |                                                            |
| `dale_chall_readability_score_v2` |    ❌     |                                                            |
| `lix`                             |    ❌     |                                                            |
| `rix`                             |    ❌     |                                                            |
| `fernandez_huerta`                |    ❌     | Spanish                                                    |
| `szigriszt_pazos`                 |    ❌     | Spanish                                                    |
| `gutierrez_polini`                |    ❌     | Spanish                                                    |
| `crawford`                        |    ❌     | Spanish                                                    |
| `gulpease_index`                  |    ❌     | Italian                                                    |
| `wiener_sachtextformel`           |    ❌     | German                                                     |
| `osman`                           |    ❌     | Arabic                                                     |

### Parity

<!-- bench:parity:start -->
Scores are compared against `textstat` over 1000 Wikipedia articles (up to 5000 chars each): **99.98% of 11000 comparisons match exactly**, and the largest disagreement anywhere is 0.049566.

| metric | avg delta | max delta |
| --- | --- | --- |
| flesch_reading_ease | 0.000000 | 0.000000 |
| flesch_kincaid_grade | 0.000000 | 0.000000 |
| automated_readability_index | 0.000000 | 0.000000 |
| coleman_liau_index | 0.000000 | 0.000000 |
| dale_chall_readability_score | 0.000000 | 0.000000 |
| gunning_fog | 0.000050 | 0.049566 |
| smog_index | 0.000000 | 0.000000 |
| linsear_write_formula | 0.000000 | 0.000000 |
| mcalpine_eflaw | 0.000000 | 0.000000 |
| spache_readability | 0.000011 | 0.010657 |
| reading_time | 0.000000 | 0.000000 |

_Generated from `5d3aab1` on 2026-07-25, python 3.12.4 vs textstat 0.7.13, on Windows-11-10.0.26200-SP0._
<!-- bench:parity:end -->

### Performance

<!-- bench:perf:start -->
One call per metric over 100 concatenated Wikipedia articles (0.46 MB), median of 5. Both libraries are warmed first, so these are steady-state numbers with lazy resource loading excluded.

| metric | textstat-rs (ms) | textstat (ms) | speedup |
| --- | --- | --- | --- |
| flesch_reading_ease | 39.68 | 145.02 | 3.65x |
| flesch_kincaid_grade | 34.37 | 149.34 | 4.35x |
| automated_readability_index | 16.99 | 47.21 | 2.78x |
| coleman_liau_index | 14.81 | 60.34 | 4.07x |
| dale_chall_readability_score | 29.23 | 180.36 | 6.17x |
| gunning_fog | 28.62 | 192.56 | 6.73x |
| smog_index | 28.09 | 204.73 | 7.29x |
| linsear_write_formula | 0.05 | 3.79 | 79.81x |
| mcalpine_eflaw | 18.05 | 43.65 | 2.42x |
| spache_readability | 30.37 | 192.59 | 6.34x |
| reading_time | 0.91 | 13.23 | 14.58x |

On top of that, the first call in a fresh process pays a one-off load of the syllable and word-list resources: up to 32 ms for `textstat-rs` against 455 ms for `textstat`.

_Generated from `5d3aab1` on 2026-07-25, python 3.12.4 vs textstat 0.7.13, on Windows-11-10.0.26200-SP0._
<!-- bench:perf:end -->

