:INFO [align:center] pilcrow Paste from Word, a PDF, an email client or a CMS and you get sentences broken by hard line breaks, runs of double spaces, non-breaking spaces where they do not belong, and smart quotes that survived three round trips and then did not. This library turns that into clean paragraphs. It does not do anything else, and that is the whole design. | :INFO Who This Is For You maintain something that accepts text a human pasted in from somewhere else. A CMS field, a contact form, a note-taking app, an import pipeline. You have written the same three regexes at least twice. They were subtly wrong both times. The bug that made you write them the second time came from a French document, where the non-breaking space before a colon is correct and must be kept. | :CHECKLIST Install [ ] pip install pilcrow [ ] Python 3.9 or newer [ ] No dependencies, and none planned. There is nothing else to install [ ] Optional: pip install "pilcrow[cli]" if you want the pilcrow command | :INFO.half The One Thing It Does normalise() takes a string and returns a string. It joins lines broken mid-sentence, keeps the breaks that were deliberate, collapses whitespace runs without touching indentation inside fenced blocks, and leaves typographic characters alone unless you ask otherwise. | :INFO.half How It Decides A break is deliberate if the line before it ends in sentence punctuation, is shorter than the running median line length, or starts a list. Three rules, in that order. They are wrong for poetry, and poetry is out of scope in the README rather than in a heuristic. | :STATS | :INFO What It Will Not Do It does not detect language, spellcheck, strip HTML, convert Markdown or guess what you meant. Each of those has been requested and declined, and the reasoning sits in the issue thread rather than behind a wontfix label. If you need HTML stripping, use something that actually parses HTML. A regex that half understands HTML is how the second bug on this page started. | :QUOTE [quotetype:plain, subtitle:from issue 88] I deleted sixty lines of accumulated regex and replaced them with one function call. The French quotation marks finally survived the round trip. | :CHECKLIST Your first run [ ] Call normalise(text) and read the output before you configure anything [ ] If a break you wanted was removed, pass keep_breaks=True [ ] If a non-breaking space you needed was removed, pass locale="fr" [ ] Run pilcrow --diff against a real file from your corpus, not a synthetic one [ ] Only then decide whether you need the other two functions | :INFO Where To Go Next The README is the documentation. There is no separate docs site, because there is not enough surface area to justify one and a docs site that lags the README is worse than none at all. The API reference fits on one page. If something reads as unclear, that is a documentation bug and it is worth an issue. | :LINK https://pypi.org/project/pilcrow/ pilcrow on PyPI | :LINK https://github.com/ellamaki/pilcrow Source and issue tracker