cleave-sbd 0.2.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. cleave_sbd-0.2.0b1/.github/ISSUE_TEMPLATE/bug_report.md +54 -0
  2. cleave_sbd-0.2.0b1/.github/workflows/python-package.yml +43 -0
  3. cleave_sbd-0.2.0b1/.gitignore +78 -0
  4. cleave_sbd-0.2.0b1/CHANGELOG.md +44 -0
  5. cleave_sbd-0.2.0b1/CONTRIBUTING.md +64 -0
  6. cleave_sbd-0.2.0b1/LICENSE +21 -0
  7. cleave_sbd-0.2.0b1/PKG-INFO +204 -0
  8. cleave_sbd-0.2.0b1/README.md +169 -0
  9. cleave_sbd-0.2.0b1/benchmarking/benchmark_output.txt +18 -0
  10. cleave_sbd-0.2.0b1/benchmarking/bigtext_speed_benchmark.py +575 -0
  11. cleave_sbd-0.2.0b1/benchmarking/english_accuracy_benchmark.py +159 -0
  12. cleave_sbd-0.2.0b1/profiling/profile_benchmarks.py +109 -0
  13. cleave_sbd-0.2.0b1/profiling/profile_normalizer.py +102 -0
  14. cleave_sbd-0.2.0b1/pyproject.toml +140 -0
  15. cleave_sbd-0.2.0b1/src/csbd/__init__.py +11 -0
  16. cleave_sbd-0.2.0b1/src/csbd/disambiguator.py +380 -0
  17. cleave_sbd-0.2.0b1/src/csbd/language/__init__.py +17 -0
  18. cleave_sbd-0.2.0b1/src/csbd/language/configs/am.toml +8 -0
  19. cleave_sbd-0.2.0b1/src/csbd/language/configs/ar.toml +40 -0
  20. cleave_sbd-0.2.0b1/src/csbd/language/configs/bg.toml +80 -0
  21. cleave_sbd-0.2.0b1/src/csbd/language/configs/da.toml +521 -0
  22. cleave_sbd-0.2.0b1/src/csbd/language/configs/de.toml +209 -0
  23. cleave_sbd-0.2.0b1/src/csbd/language/configs/el.toml +8 -0
  24. cleave_sbd-0.2.0b1/src/csbd/language/configs/en.toml +260 -0
  25. cleave_sbd-0.2.0b1/src/csbd/language/configs/es.toml +355 -0
  26. cleave_sbd-0.2.0b1/src/csbd/language/configs/fa.toml +17 -0
  27. cleave_sbd-0.2.0b1/src/csbd/language/configs/fr.toml +98 -0
  28. cleave_sbd-0.2.0b1/src/csbd/language/configs/hi.toml +9 -0
  29. cleave_sbd-0.2.0b1/src/csbd/language/configs/hy.toml +7 -0
  30. cleave_sbd-0.2.0b1/src/csbd/language/configs/it.toml +2363 -0
  31. cleave_sbd-0.2.0b1/src/csbd/language/configs/ja.toml +9 -0
  32. cleave_sbd-0.2.0b1/src/csbd/language/configs/kk.toml +306 -0
  33. cleave_sbd-0.2.0b1/src/csbd/language/configs/mr.toml +7 -0
  34. cleave_sbd-0.2.0b1/src/csbd/language/configs/my.toml +8 -0
  35. cleave_sbd-0.2.0b1/src/csbd/language/configs/nl.toml +1573 -0
  36. cleave_sbd-0.2.0b1/src/csbd/language/configs/pl.toml +137 -0
  37. cleave_sbd-0.2.0b1/src/csbd/language/configs/ru.toml +78 -0
  38. cleave_sbd-0.2.0b1/src/csbd/language/configs/sk.toml +236 -0
  39. cleave_sbd-0.2.0b1/src/csbd/language/configs/ur.toml +8 -0
  40. cleave_sbd-0.2.0b1/src/csbd/language/configs/zh.toml +5 -0
  41. cleave_sbd-0.2.0b1/src/csbd/language/lang.py +179 -0
  42. cleave_sbd-0.2.0b1/src/csbd/language/protocols.py +35 -0
  43. cleave_sbd-0.2.0b1/src/csbd/normalizer.py +246 -0
  44. cleave_sbd-0.2.0b1/src/csbd/processors/__init__.py +29 -0
  45. cleave_sbd-0.2.0b1/src/csbd/processors/abbreviation.py +299 -0
  46. cleave_sbd-0.2.0b1/src/csbd/processors/lists.py +480 -0
  47. cleave_sbd-0.2.0b1/src/csbd/py.typed +0 -0
  48. cleave_sbd-0.2.0b1/src/csbd/rules/__init__.py +231 -0
  49. cleave_sbd-0.2.0b1/src/csbd/rules/abbreviation.py +234 -0
  50. cleave_sbd-0.2.0b1/src/csbd/rules/boundary.py +187 -0
  51. cleave_sbd-0.2.0b1/src/csbd/rules/disambiguation.py +71 -0
  52. cleave_sbd-0.2.0b1/src/csbd/rules/normalizer.py +72 -0
  53. cleave_sbd-0.2.0b1/src/csbd/rules/pua.py +133 -0
  54. cleave_sbd-0.2.0b1/src/csbd/segmenter.py +198 -0
  55. cleave_sbd-0.2.0b1/tests/__init__.py +0 -0
  56. cleave_sbd-0.2.0b1/tests/data/issues.toml +111 -0
  57. cleave_sbd-0.2.0b1/tests/data/lang/amharic.toml +4 -0
  58. cleave_sbd-0.2.0b1/tests/data/lang/arabic.toml +20 -0
  59. cleave_sbd-0.2.0b1/tests/data/lang/armenian.toml +104 -0
  60. cleave_sbd-0.2.0b1/tests/data/lang/bulgarian.toml +16 -0
  61. cleave_sbd-0.2.0b1/tests/data/lang/burmese.toml +4 -0
  62. cleave_sbd-0.2.0b1/tests/data/lang/chinese.toml +8 -0
  63. cleave_sbd-0.2.0b1/tests/data/lang/danish.toml +196 -0
  64. cleave_sbd-0.2.0b1/tests/data/lang/deutsch.toml +140 -0
  65. cleave_sbd-0.2.0b1/tests/data/lang/dutch.toml +12 -0
  66. cleave_sbd-0.2.0b1/tests/data/lang/english.toml +193 -0
  67. cleave_sbd-0.2.0b1/tests/data/lang/english_clean.toml +504 -0
  68. cleave_sbd-0.2.0b1/tests/data/lang/french.toml +20 -0
  69. cleave_sbd-0.2.0b1/tests/data/lang/greek.toml +4 -0
  70. cleave_sbd-0.2.0b1/tests/data/lang/hindi.toml +4 -0
  71. cleave_sbd-0.2.0b1/tests/data/lang/italian.toml +144 -0
  72. cleave_sbd-0.2.0b1/tests/data/lang/japanese.toml +20 -0
  73. cleave_sbd-0.2.0b1/tests/data/lang/kazakh.toml +52 -0
  74. cleave_sbd-0.2.0b1/tests/data/lang/marathi.toml +20 -0
  75. cleave_sbd-0.2.0b1/tests/data/lang/persian.toml +4 -0
  76. cleave_sbd-0.2.0b1/tests/data/lang/polish.toml +4 -0
  77. cleave_sbd-0.2.0b1/tests/data/lang/russian.toml +168 -0
  78. cleave_sbd-0.2.0b1/tests/data/lang/slovak.toml +20 -0
  79. cleave_sbd-0.2.0b1/tests/data/lang/spanish.toml +144 -0
  80. cleave_sbd-0.2.0b1/tests/data/lang/urdu.toml +4 -0
  81. cleave_sbd-0.2.0b1/tests/data/list_items.toml +90 -0
  82. cleave_sbd-0.2.0b1/tests/data/normalizer.toml +8 -0
  83. cleave_sbd-0.2.0b1/tests/data/pdf.toml +24 -0
  84. cleave_sbd-0.2.0b1/tests/loaders.py +278 -0
  85. cleave_sbd-0.2.0b1/tests/test_backtracking.py +48 -0
  86. cleave_sbd-0.2.0b1/tests/test_languages.py +84 -0
  87. cleave_sbd-0.2.0b1/tests/test_list_masking.py +45 -0
  88. cleave_sbd-0.2.0b1/tests/test_normalizer.py +34 -0
  89. cleave_sbd-0.2.0b1/tests/test_regressions.py +49 -0
  90. cleave_sbd-0.2.0b1/tests/test_segmenter.py +174 -0
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Create a report and test case to help us improve cleave-sbd
4
+ title: "[BUG] "
5
+ labels: ["bug"]
6
+ assignees: ""
7
+
8
+ ---
9
+
10
+ ### Description
11
+ A clear and concise description of what the bug is.
12
+
13
+ ### Reproduction Code
14
+
15
+ ```python
16
+ import csbd
17
+
18
+ seg = csbd.Segmenter(language="en", clean=False, char_span=False)
19
+ text = "Your sample text here."
20
+ sentences = seg.segment(text)
21
+ print(sentences)
22
+ ```
23
+
24
+ ### Expected Behavior
25
+ A clear and concise description of what sentences should have been segmented.
26
+
27
+ ```python
28
+ ["Expected sentence 1.", "Expected sentence 2."]
29
+ ```
30
+
31
+ ### Actual Behavior
32
+ The actual output returned by `cleave-sbd`.
33
+
34
+ ```python
35
+ ["Actual sentence 1."]
36
+ ```
37
+
38
+ ### Environment Information
39
+ - Python version (e.g., `3.11.8`, `3.12.2`):
40
+ - `cleave-sbd` version (e.g., `0.1.0`):
41
+ - Operating System (e.g., Linux, macOS, Windows):
42
+
43
+ ### Additional Context
44
+ Add any other context, stack traces, or screenshots here.
45
+
46
+ <details>
47
+ <summary>Traceback (if applicable)</summary>
48
+
49
+ ```
50
+ Paste traceback here
51
+ ```
52
+
53
+ </details>
54
+
@@ -0,0 +1,43 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v7
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v7
23
+ with:
24
+ enable-cache: true
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --all-groups
29
+
30
+ - name: Run Ruff Linter
31
+ run: uv run ruff check .
32
+
33
+ - name: Run Ruff Formatter Check
34
+ run: uv run ruff format --check .
35
+
36
+ - name: Run Strict Type Checking
37
+ run: uv run basedpyright .
38
+
39
+ - name: Run Pytest Suite
40
+ run: uv run pytest
41
+
42
+ - name: Verify Package Build
43
+ run: uv build
@@ -0,0 +1,78 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Environments & Package Managers
8
+ .venv/
9
+ venv/
10
+ ENV/
11
+ env/
12
+ .python-version
13
+ .uv/
14
+ .pdm-build/
15
+ .pdm-python
16
+
17
+ # Distribution / Packaging
18
+ dist/
19
+ build/
20
+ *.egg-info/
21
+ *.egg
22
+ develop-eggs/
23
+ .eggs/
24
+ parts/
25
+ wheels/
26
+ sdist/
27
+ .installed.cfg
28
+
29
+ # Testing & Coverage
30
+ .pytest_cache/
31
+ .tox/
32
+ .nox/
33
+ .coverage
34
+ .coverage.*
35
+ htmlcov/
36
+ coverage.xml
37
+ *.cover
38
+ .hypothesis/
39
+ ignored_tests/
40
+ personal_notes/
41
+ benchmarks/
42
+
43
+ # Type Checking & Linting (Ruff, Basedpyright, Mypy, etc.)
44
+ .ruff_cache/
45
+ .mypy_cache/
46
+ .dmypy.json
47
+ dmypy.json
48
+ .pyright/
49
+ .pyre/
50
+ .pytype/
51
+
52
+ # Environment Variables & Secrets
53
+ .env
54
+ .env.*
55
+ !.env.example
56
+
57
+ # Editors & IDEs (Zed, VS Code, Cursor, JetBrains)
58
+ .zed/
59
+ .vscode/*
60
+ !.vscode/settings.json
61
+ !.vscode/tasks.json
62
+ !.vscode/launch.json
63
+ !.vscode/extensions.json
64
+ .cursor/
65
+ .idea/
66
+ *.sublime-project
67
+ *.sublime-workspace
68
+
69
+ # Documentation
70
+ docs/_build/
71
+ site/
72
+
73
+ # OS-generated files
74
+ .DS_Store
75
+ Thumbs.db
76
+ AGENTS.md
77
+ uv.lock
78
+ validate.sh
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0-beta.1] - 2026-08-24
9
+
10
+ ### Added
11
+ - **Memory-Bounded Sentence Streaming API**: Introduced `Segmenter.stream(text, chunk_paragraphs=1000)` lazy generator for constant-memory corpus processing with exact global character offset tracking (`TextSpan`).
12
+ - **Modular Processor Architecture**: Decomposed monolithic disambiguator into specialized single-responsibility modules:
13
+ - `csbd.processors.lists`: AST-based sequential validation for numbered, alphabetical, and Roman numeral lists.
14
+ - `csbd.processors.abbreviation`: LRU-cached category compilation, prepositive matching, and linguistic abbreviation masking.
15
+ - `csbd.disambiguator`: Lean, functional pipeline orchestrator.
16
+ - **Rules Package Separation**: Extracted all pre-compiled regex tables, PUA sentinels, and replacement definitions into `csbd.rules`.
17
+ - **ReDoS Hardening & Catastrophic Backtracking Defenses**: Audited and hardened nested lookahead/group expressions with non-backtracking atomic lookaheads, backed by `tests/test_backtracking.py`.
18
+ - **Benchmarking & Profiling Suite**: Added `profiling/profile_benchmarks.py` for automated profiling and throughput benchmarking.
19
+
20
+ ### Changed
21
+ - **Package Layout & Rebranding**: Migrated from `pragmatic_sbd` to `cleave-sbd` under standard `src/` directory layout.
22
+ - **$O(1)$ Hash Set Scanner Optimization**: Replaced massive 100+ branch regex alternations with single-pass word boundary scanners (`STANDARD_ABBR_SCAN_REGEX`) and compiled C-level `frozenset` lookups.
23
+ - **Fast-Path Character Short-Circuiting**: Added SIMD `str.__contains__` (`memchr`) short-circuiting to skip unused paired delimiter and punctuation regex passes.
24
+ - **Zero-Allocation Span Tracking**: Replaced heap-allocated `.strip()` / `.lstrip()` operations in `trim_span` with pointer index scanning, eliminating over 700,000 intermediate string allocations.
25
+ - **Single-Pass Acronym Matching**: Optimized uppercase initial parsing to match arbitrary consecutive initials in a single pass (`(?:[A-ZА-ЯЁ]\.)+`).
26
+ - **Documentation & Typing**: Added full Google-style docstrings and normalized all variables across the codebase, maintaining zero errors in `basedpyright` strict mode.
27
+ - **Externalized Test Suite**: Converted test fixtures to structured `.toml` datasets with strongly typed `NamedTuple` boundaries.
28
+
29
+ ### Performance
30
+ - Single-threaded throughput increased to **>1.3 MB/s** (~3.45s unprofiled execution on 5.13 MB / 176,000 sentences).
31
+
32
+ ---
33
+
34
+ ## [0.1.0] - 2026-08-18
35
+
36
+ ### Added
37
+ - Complete modern rewrite and architecture of the sentence boundary disambiguation engine.
38
+ - Declarative, pre-compiled regular expression pipeline replacing procedural loops.
39
+ - Pure functional, length-preserving Private Use Area (PUA) sentinel substitutions (`\ue000`–`\ue009`) guaranteeing $1:1$ character offset preservation for span computation.
40
+ - Comprehensive PEP 561 type hints (`py.typed`) with zero errors in `basedpyright` strict mode.
41
+ - Standard PEP 517/621/735 packaging via `pyproject.toml` with `hatchling` and `uv`.
42
+ - Multilingual rule sets for 22 languages: `am`, `ar`, `bg`, `da`, `de`, `el`, `en`, `es`, `fa`, `fr`, `hi`, `hy`, `it`, `ja`, `kk`, `mr`, `nl`, `pl`, `ru`, `sk`, `ur`, `zh`.
43
+ - Zero runtime dependencies.
44
+
@@ -0,0 +1,64 @@
1
+ # Contributing to cleave-sbd
2
+
3
+ Thank you for your interest in contributing to **cleave-sbd**!
4
+
5
+ ## Development Setup
6
+
7
+ We use [`uv`](https://github.com/astral-sh/uv) for fast, deterministic dependency management and virtual environments:
8
+
9
+ ```bash
10
+ # 1. Clone the repository
11
+ git clone https://github.com/sblasing/cleave-sbd.git
12
+ cd cleave-sbd
13
+
14
+ # 2. Sync all development dependencies
15
+ uv sync --all-groups
16
+ ```
17
+
18
+ ## Running Tests and Diagnostics
19
+
20
+ Before submitting a pull request, ensure all tests, linting, formatting, and type checks pass:
21
+
22
+ ```bash
23
+ # Run pytest test suite
24
+ uv run pytest
25
+
26
+ # Run type checker (strict mode)
27
+ uv run basedpyright src/
28
+
29
+ # Run linter checks
30
+ uv run ruff check .
31
+
32
+ # Check formatting
33
+ uv run ruff format --check src/
34
+ ```
35
+
36
+ ## Core Architectural Principles
37
+
38
+ When making contributions, adhere to the core design principles of `cleave-sbd`:
39
+
40
+ 1. **Strict Typing (PEP 561):** All code in `src/csbd/` must be fully type-annotated and pass `basedpyright` in strict mode with zero errors or warnings.
41
+ 2. **Length Invariance:** Any preprocessing, masking, or normalization supporting character spans (`char_span=True`) must maintain exact $1:1$ character length preservation using Private Use Area (PUA) sentinels (`\ue000`–`\ue009`). Never add or remove characters in span mode.
42
+ 3. **Declarative & Immutable:** Prefer pre-compiled regular expressions (`re.compile`), immutable data structures (`frozenset`, frozen dataclasses), and pure functional transformations over procedural loops or stateful mutations.
43
+ 4. **Zero Runtime Dependencies:** `cleave-sbd` is a pure-Python library with zero external runtime dependencies.
44
+
45
+ ## Contributing Workflows
46
+
47
+ ### Fixing Bugs
48
+
49
+ 1. Add a minimal reproducing test case to [`tests/regression/test_issues.py`](tests/regression/test_issues.py).
50
+ 2. Implement the fix in `src/csbd/` ensuring length preservation and strict typing.
51
+ 3. Verify that all tests and lint checks pass.
52
+
53
+ ### Adding or Enhancing Language Support
54
+
55
+ 1. Language rule sets live in [`src/csbd/language/configs/`](src/csbd/language/configs/).
56
+ 2. Create or update the language module (e.g. `src/csbd/language/configs/<language>.toml`) using typed rules and frozenset collections.
57
+ 3. Register the language in [`src/csbd/language/lang.py`](src/csbd/language/lang.py).
58
+ 4. Add comprehensive test cases in `tests/lang/test_<language>.py`.
59
+
60
+ ## Pull Request Guidelines
61
+
62
+ - Branch naming: `feat/<feature-name>`, `fix/<bug-name>`, or `refactor/<description>`.
63
+ - Commit messages: Follow [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat:`, `fix:`, `docs:`, `chore:`).
64
+ - Ensure all CI checks (pytest, ruff, basedpyright) pass locally before pushing.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scott Blasing
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.5
2
+ Name: cleave-sbd
3
+ Version: 0.2.0b1
4
+ Summary: High-performance, strictly-typed sentence boundary disambiguation (Pragmatic SBD)
5
+ Project-URL: Homepage, https://github.com/sblasing/cleave-sbd
6
+ Project-URL: Repository, https://github.com/sblasing/cleave-sbd
7
+ Project-URL: Issues, https://github.com/sblasing/cleave-sbd/issues
8
+ Project-URL: Changelog, https://github.com/sblasing/cleave-sbd/blob/main/CHANGELOG.md
9
+ Author-email: Scott Blasing <sdblasing@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: natural-language-processing,nlp,sentence-boundary-disambiguation,sentence-segmentation,text-processing
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Topic :: Text Processing :: Linguistic
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.11
28
+ Provides-Extra: dev
29
+ Requires-Dist: basedpyright>=1.39.0; extra == 'dev'
30
+ Requires-Dist: build>=1.5.0; extra == 'dev'
31
+ Requires-Dist: pytest>=9.0.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.16.0; extra == 'dev'
33
+ Requires-Dist: twine>=7.0.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # cleave-sbd: Sentence Boundary Disambiguation
37
+
38
+ [![CI](https://github.com/sblasing/cleave-sbd/actions/workflows/python-package.yml/badge.svg)](https://github.com/sblasing/cleave-sbd/actions/workflows/python-package.yml)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+ [![Python: 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
41
+ [![Typing: Strict](https://img.shields.io/badge/typing-strict-green.svg)](https://peps.python.org/pep-0561/)
42
+ [![Code Style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
43
+
44
+ **cleave-sbd** is a high-performance, strictly-typed sentence boundary disambiguation (SBD) engine. It isolates sentence boundaries across complex edge cases—including abbreviations, honorifics, numbers, lists, ellipses, and quotations—with zero machine learning dependencies.
45
+
46
+ ---
47
+
48
+ ## Features
49
+
50
+ * **Zero Heavy Dependencies:** Pure Python logic without bloated neural models, PyTorch, or GPU requirements.
51
+ * **Declarative & Length-Preserving:** Length-preserving PUA sentinel substitutions ensure $1:1$ character offset invariance for precise span extraction.
52
+ * **Strictly Typed:** Fully typed and verified in strict mode with Basedpyright/Pyright (PEP 561 compliant with `py.typed`).
53
+ * **Multilingual Support:** Out-of-the-box rule sets for 22 languages.
54
+ * **High Performance:** Pre-compiled regular expressions and immutable lookup tables.
55
+
56
+ ---
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install cleave-sbd
62
+ ```
63
+
64
+
65
+ Or with `uv`:
66
+
67
+ ```bash
68
+ uv add cleave-sbd
69
+ ```
70
+
71
+
72
+ ---
73
+
74
+ ## Quickstart
75
+
76
+ python
77
+ import csbd
78
+
79
+ text = "My name is Jonas E. Smith. Please turn to p. 55."
80
+ seg = csbd.Segmenter(language="en", clean=False)
81
+
82
+ sentences = seg.segment(text)
83
+ print(sentences)
84
+ # Output:
85
+ # ('My name is Jonas E. Smith.', 'Please turn to p. 55.')
86
+
87
+
88
+
89
+ ### Character Span Mode
90
+
91
+ Extract start and end character offsets alongside segmented sentences:
92
+
93
+ python
94
+ import csbd
95
+
96
+ text = "Hello world! This is a test."
97
+ seg = csbd.Segmenter(language="en", char_span=True)
98
+
99
+ spans = seg.segment(text)
100
+ for span in spans:
101
+ print(f"{span.sent!r} -> [{span.start}:{span.end}]")
102
+ # Output:
103
+ # 'Hello world!' ->
104
+ # 'This is a test.' ->
105
+
106
+
107
+
108
+ ---
109
+
110
+ ## Parameters
111
+
112
+ | Parameter | Type | Default | Description |
113
+ | --- | --- | --- | --- |
114
+ | `language` | `str` | `"en"` | Two-letter ISO 639-1 language code (e.g., `"en"`, `"de"`, `"fr"`, `"es"`, `"ja"`). |
115
+ | `clean` | `bool` | `False` | When `True`, normalizes noisy formatting (e.g., consecutive whitespace, unusual line breaks) before splitting. |
116
+ | `doc_type` | `str` | `""` | Set to `"pdf"` for OCR/PDF extracted line break handling. Requires `clean=True`. |
117
+ | `char_span` | `bool` | `False` | When `True`, returns character offset spans (`TextSpan`) instead of plain strings. |
118
+
119
+ ---
120
+
121
+ ## Supported Languages
122
+
123
+ | Code | Language | Code | Language | Code | Language |
124
+ | --- | --- | --- | --- | --- | --- |
125
+ | `am` | Amharic | `el` | Greek | `mr` | Marathi |
126
+ | `ar` | Arabic | `en` | English | `nl` | Dutch |
127
+ | `bg` | Bulgarian | `es` | Spanish | `pl` | Polish |
128
+ | `da` | Danish | `fa` | Persian | `ru` | Russian |
129
+ | `de` | German | `fr` | French | `sk` | Slovak |
130
+ | `hy` | Armenian | `hi` | Hindi | `ur` | Urdu |
131
+ | `it` | Italian | `ja` | Japanese | `zh` | Chinese |
132
+ | `kk` | Kazakh | | | | |
133
+
134
+ ---
135
+
136
+ ## Architecture & Engineering Philosophy
137
+
138
+ `cleave-sbd` is engineered under strict architectural constraints to guarantee high cohesion, loose coupling, and C-level execution speed:
139
+
140
+ 1. **Standard Library Only:** Built exclusively with Python standard library primitives (`tomllib`, `typing`, `dataclasses`, `itertools`). Zero external runtime dependencies, zero supply-chain vulnerabilities, and zero version drift.
141
+ 2. **Strict Typing & Boundary Sanitization:** End-to-end type safety verified under strict type checkers. Untyped dictionaries (`dict[str, Any]`) are restricted entirely to raw TOML ingestion and mapped immediately to concrete types.
142
+ 3. **Separation of Data and Logic:** Data models are immutable, memory-optimized, and logic-free via `@dataclass(frozen=True, slots=True)`. Computational logic is structured strictly as pure, deterministic functions (data-in, data-out) with zero internal state mutations.
143
+ 4. **Loose Coupling via Protocols & Dependency Injection:** Logic components depend on abstract `typing.Protocol` contracts rather than concrete implementations. Configurations and rule tables are injected directly into pure pipelines.
144
+ 5. **C-Speed Execution & Zero-Copy Primitives:** Minimal allocation overhead using CPython built-ins, pre-compiled regular expressions, generator streaming (`Sequence[T]`, `Iterable[T]`), and immutable `tuple` returns.
145
+ 6. **Unidirectional Dependency Flow:** Clean, single-direction import hierarchy: `Config Schemas → Parsers → Domain Logic → Public API`. Core transformation logic never imports from configuration or entrypoint layers.
146
+
147
+ ---
148
+
149
+ ## Performance & Speed Benchmarks
150
+
151
+ Benchmarks evaluated on the **Complete Works of William Shakespeare** (`pg100.txt`):
152
+
153
+ * **File Size:** 5.31 MB (5,442,036 bytes)
154
+ * **Text Volume:** 5,378,655 characters | 966,506 words
155
+
156
+ ### Benchmark Results
157
+
158
+ | Engine | Sentences Found | Mean Latency | Min Latency | Throughput | Status / Speedup |
159
+ | --- | --- | --- | --- | --- | --- |
160
+ | **`cleave-sbd` (`clean=False`)** | 175,998 | 3,407.85 ms | 3,378.60 ms | 1.52 MB/s | 1.00x (Baseline) |
161
+ | **`cleave-sbd` (`clean=True`)** | 176,010 | 3,533.35 ms | 3,469.87 ms | 1.47 MB/s | 0.96x |
162
+ | **`cleave-sbd` (`char_span=True`)** | 175,998 | 3,832.14 ms | 3,689.56 ms | 1.35 MB/s | 0.89x |
163
+ | **`spaCy sentencizer`** | 109,084 | 4,862.67 ms | 4,758.62 ms | 1.07 MB/s | 0.97x |
164
+ | **`BlingFire`** | 107,489 | 164.11 ms | 161.32 ms | 31.62 MB/s | 27.77x |
165
+ | **`NLTK sent_tokenize`**| 105,488 | 726.35 ms | 724.30 ms | 7.15 MB/s | 6.27x |
166
+ | **`Syntok`** | 112,612 | 3,871.09 ms | 3,811.82 ms | 1.34 MB/s | 1.18x |
167
+ | **`Stanza`** | 127,102 | 48,151.78 ms | 45,269.77 ms | 0.11 MB/s | 0.09x *(~10.6x slower)* |
168
+ | **`spaCy en_core_web_sm`** | — | — | — | — | **Refused / Setup Failure** |
169
+ | **`pySBD`** | — | >900,000 ms | — | <0.005 MB/s | **DNF (Timed out >15 min)** |
170
+
171
+ ---
172
+
173
+ ### Key Takeaways & Failure Analysis
174
+
175
+ * **pySBD Asymptotic Hang (>15 Minutes):** `pySBD` hits an $O(N^2)$ algorithmic wall on multi-megabyte corpora. Due to un-vectorized line-by-line loops, dynamic runtime regex recompilation, and repeated string allocations, processing the 5.3 MB corpus locked the CPU thread for **over 15 minutes without completing**. In contrast, `cleave-sbd` finished the exact same segmentation in **3.41 seconds**.
176
+ * **spaCy Pipeline Lockout:** spaCy failed to run out-of-the-box due to rigid external model weight requirements and initialization overhead, refusing processing without dedicated secondary environment bootstrapping.
177
+ * **Granular Boundary Precision:** `cleave-sbd` detected **176,430** valid sentence boundaries (~49,000–70,000 more than Stanza, NLTK, or BlingFire) by accurately segmenting dramatic verse, dialogue cues, character tags, and archaic typography rather than collapsing them into single run-on blocks.
178
+ * **10.6x Faster than Neural Pipelines:** Pure-Python pre-compiled state machines beat Stanford Stanza's PyTorch neural pipeline (`4.56 s` vs `48.15 s`) on a single CPU core with zero external C++ or CUDA dependencies.
179
+ * **Zero-Cost Character Spans:** Full character offset tracking (`char_span=True`) adds only **~200 ms** of latency over 5.3 MB, sustaining **1.09 MB/s** throughput.
180
+
181
+ ---
182
+
183
+ ### Reproduce Benchmarks
184
+
185
+ ```bash
186
+ uv run --with nltk,stanza,blingfire,syntok python tests/bigtext_speed_benchmark.py
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Acknowledgments & Attribution
192
+
193
+ `cleave-sbd` is an independent, complete rewrite designed from the ground up as a modern, declarative, strictly-typed sentence boundary disambiguation engine.
194
+
195
+ Sincere attribution and gratitude are given to the projects whose compiled linguistic heuristics and rule sets inspired this library:
196
+
197
+ * **[Pragmatic Segmenter](https://github.com/diasks2/pragmatic_segmenter)** by Kevin S. Dias (Ruby)
198
+ * **[pySBD](https://github.com/nipunsadvilkar/pySBD)** by Nipun Sadvilkar (Python)
199
+
200
+ ---
201
+
202
+ ## License
203
+
204
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,169 @@
1
+ # cleave-sbd: Sentence Boundary Disambiguation
2
+
3
+ [![CI](https://github.com/sblasing/cleave-sbd/actions/workflows/python-package.yml/badge.svg)](https://github.com/sblasing/cleave-sbd/actions/workflows/python-package.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Python: 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
6
+ [![Typing: Strict](https://img.shields.io/badge/typing-strict-green.svg)](https://peps.python.org/pep-0561/)
7
+ [![Code Style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
8
+
9
+ **cleave-sbd** is a high-performance, strictly-typed sentence boundary disambiguation (SBD) engine. It isolates sentence boundaries across complex edge cases—including abbreviations, honorifics, numbers, lists, ellipses, and quotations—with zero machine learning dependencies.
10
+
11
+ ---
12
+
13
+ ## Features
14
+
15
+ * **Zero Heavy Dependencies:** Pure Python logic without bloated neural models, PyTorch, or GPU requirements.
16
+ * **Declarative & Length-Preserving:** Length-preserving PUA sentinel substitutions ensure $1:1$ character offset invariance for precise span extraction.
17
+ * **Strictly Typed:** Fully typed and verified in strict mode with Basedpyright/Pyright (PEP 561 compliant with `py.typed`).
18
+ * **Multilingual Support:** Out-of-the-box rule sets for 22 languages.
19
+ * **High Performance:** Pre-compiled regular expressions and immutable lookup tables.
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install cleave-sbd
27
+ ```
28
+
29
+
30
+ Or with `uv`:
31
+
32
+ ```bash
33
+ uv add cleave-sbd
34
+ ```
35
+
36
+
37
+ ---
38
+
39
+ ## Quickstart
40
+
41
+ python
42
+ import csbd
43
+
44
+ text = "My name is Jonas E. Smith. Please turn to p. 55."
45
+ seg = csbd.Segmenter(language="en", clean=False)
46
+
47
+ sentences = seg.segment(text)
48
+ print(sentences)
49
+ # Output:
50
+ # ('My name is Jonas E. Smith.', 'Please turn to p. 55.')
51
+
52
+
53
+
54
+ ### Character Span Mode
55
+
56
+ Extract start and end character offsets alongside segmented sentences:
57
+
58
+ python
59
+ import csbd
60
+
61
+ text = "Hello world! This is a test."
62
+ seg = csbd.Segmenter(language="en", char_span=True)
63
+
64
+ spans = seg.segment(text)
65
+ for span in spans:
66
+ print(f"{span.sent!r} -> [{span.start}:{span.end}]")
67
+ # Output:
68
+ # 'Hello world!' ->
69
+ # 'This is a test.' ->
70
+
71
+
72
+
73
+ ---
74
+
75
+ ## Parameters
76
+
77
+ | Parameter | Type | Default | Description |
78
+ | --- | --- | --- | --- |
79
+ | `language` | `str` | `"en"` | Two-letter ISO 639-1 language code (e.g., `"en"`, `"de"`, `"fr"`, `"es"`, `"ja"`). |
80
+ | `clean` | `bool` | `False` | When `True`, normalizes noisy formatting (e.g., consecutive whitespace, unusual line breaks) before splitting. |
81
+ | `doc_type` | `str` | `""` | Set to `"pdf"` for OCR/PDF extracted line break handling. Requires `clean=True`. |
82
+ | `char_span` | `bool` | `False` | When `True`, returns character offset spans (`TextSpan`) instead of plain strings. |
83
+
84
+ ---
85
+
86
+ ## Supported Languages
87
+
88
+ | Code | Language | Code | Language | Code | Language |
89
+ | --- | --- | --- | --- | --- | --- |
90
+ | `am` | Amharic | `el` | Greek | `mr` | Marathi |
91
+ | `ar` | Arabic | `en` | English | `nl` | Dutch |
92
+ | `bg` | Bulgarian | `es` | Spanish | `pl` | Polish |
93
+ | `da` | Danish | `fa` | Persian | `ru` | Russian |
94
+ | `de` | German | `fr` | French | `sk` | Slovak |
95
+ | `hy` | Armenian | `hi` | Hindi | `ur` | Urdu |
96
+ | `it` | Italian | `ja` | Japanese | `zh` | Chinese |
97
+ | `kk` | Kazakh | | | | |
98
+
99
+ ---
100
+
101
+ ## Architecture & Engineering Philosophy
102
+
103
+ `cleave-sbd` is engineered under strict architectural constraints to guarantee high cohesion, loose coupling, and C-level execution speed:
104
+
105
+ 1. **Standard Library Only:** Built exclusively with Python standard library primitives (`tomllib`, `typing`, `dataclasses`, `itertools`). Zero external runtime dependencies, zero supply-chain vulnerabilities, and zero version drift.
106
+ 2. **Strict Typing & Boundary Sanitization:** End-to-end type safety verified under strict type checkers. Untyped dictionaries (`dict[str, Any]`) are restricted entirely to raw TOML ingestion and mapped immediately to concrete types.
107
+ 3. **Separation of Data and Logic:** Data models are immutable, memory-optimized, and logic-free via `@dataclass(frozen=True, slots=True)`. Computational logic is structured strictly as pure, deterministic functions (data-in, data-out) with zero internal state mutations.
108
+ 4. **Loose Coupling via Protocols & Dependency Injection:** Logic components depend on abstract `typing.Protocol` contracts rather than concrete implementations. Configurations and rule tables are injected directly into pure pipelines.
109
+ 5. **C-Speed Execution & Zero-Copy Primitives:** Minimal allocation overhead using CPython built-ins, pre-compiled regular expressions, generator streaming (`Sequence[T]`, `Iterable[T]`), and immutable `tuple` returns.
110
+ 6. **Unidirectional Dependency Flow:** Clean, single-direction import hierarchy: `Config Schemas → Parsers → Domain Logic → Public API`. Core transformation logic never imports from configuration or entrypoint layers.
111
+
112
+ ---
113
+
114
+ ## Performance & Speed Benchmarks
115
+
116
+ Benchmarks evaluated on the **Complete Works of William Shakespeare** (`pg100.txt`):
117
+
118
+ * **File Size:** 5.31 MB (5,442,036 bytes)
119
+ * **Text Volume:** 5,378,655 characters | 966,506 words
120
+
121
+ ### Benchmark Results
122
+
123
+ | Engine | Sentences Found | Mean Latency | Min Latency | Throughput | Status / Speedup |
124
+ | --- | --- | --- | --- | --- | --- |
125
+ | **`cleave-sbd` (`clean=False`)** | 175,998 | 3,407.85 ms | 3,378.60 ms | 1.52 MB/s | 1.00x (Baseline) |
126
+ | **`cleave-sbd` (`clean=True`)** | 176,010 | 3,533.35 ms | 3,469.87 ms | 1.47 MB/s | 0.96x |
127
+ | **`cleave-sbd` (`char_span=True`)** | 175,998 | 3,832.14 ms | 3,689.56 ms | 1.35 MB/s | 0.89x |
128
+ | **`spaCy sentencizer`** | 109,084 | 4,862.67 ms | 4,758.62 ms | 1.07 MB/s | 0.97x |
129
+ | **`BlingFire`** | 107,489 | 164.11 ms | 161.32 ms | 31.62 MB/s | 27.77x |
130
+ | **`NLTK sent_tokenize`**| 105,488 | 726.35 ms | 724.30 ms | 7.15 MB/s | 6.27x |
131
+ | **`Syntok`** | 112,612 | 3,871.09 ms | 3,811.82 ms | 1.34 MB/s | 1.18x |
132
+ | **`Stanza`** | 127,102 | 48,151.78 ms | 45,269.77 ms | 0.11 MB/s | 0.09x *(~10.6x slower)* |
133
+ | **`spaCy en_core_web_sm`** | — | — | — | — | **Refused / Setup Failure** |
134
+ | **`pySBD`** | — | >900,000 ms | — | <0.005 MB/s | **DNF (Timed out >15 min)** |
135
+
136
+ ---
137
+
138
+ ### Key Takeaways & Failure Analysis
139
+
140
+ * **pySBD Asymptotic Hang (>15 Minutes):** `pySBD` hits an $O(N^2)$ algorithmic wall on multi-megabyte corpora. Due to un-vectorized line-by-line loops, dynamic runtime regex recompilation, and repeated string allocations, processing the 5.3 MB corpus locked the CPU thread for **over 15 minutes without completing**. In contrast, `cleave-sbd` finished the exact same segmentation in **3.41 seconds**.
141
+ * **spaCy Pipeline Lockout:** spaCy failed to run out-of-the-box due to rigid external model weight requirements and initialization overhead, refusing processing without dedicated secondary environment bootstrapping.
142
+ * **Granular Boundary Precision:** `cleave-sbd` detected **176,430** valid sentence boundaries (~49,000–70,000 more than Stanza, NLTK, or BlingFire) by accurately segmenting dramatic verse, dialogue cues, character tags, and archaic typography rather than collapsing them into single run-on blocks.
143
+ * **10.6x Faster than Neural Pipelines:** Pure-Python pre-compiled state machines beat Stanford Stanza's PyTorch neural pipeline (`4.56 s` vs `48.15 s`) on a single CPU core with zero external C++ or CUDA dependencies.
144
+ * **Zero-Cost Character Spans:** Full character offset tracking (`char_span=True`) adds only **~200 ms** of latency over 5.3 MB, sustaining **1.09 MB/s** throughput.
145
+
146
+ ---
147
+
148
+ ### Reproduce Benchmarks
149
+
150
+ ```bash
151
+ uv run --with nltk,stanza,blingfire,syntok python tests/bigtext_speed_benchmark.py
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Acknowledgments & Attribution
157
+
158
+ `cleave-sbd` is an independent, complete rewrite designed from the ground up as a modern, declarative, strictly-typed sentence boundary disambiguation engine.
159
+
160
+ Sincere attribution and gratitude are given to the projects whose compiled linguistic heuristics and rule sets inspired this library:
161
+
162
+ * **[Pragmatic Segmenter](https://github.com/diasks2/pragmatic_segmenter)** by Kevin S. Dias (Ruby)
163
+ * **[pySBD](https://github.com/nipunsadvilkar/pySBD)** by Nipun Sadvilkar (Python)
164
+
165
+ ---
166
+
167
+ ## License
168
+
169
+ MIT License. See [LICENSE](LICENSE) for details.