cellstr
Display-width aware len, slicing, padding and truncation for terminal text: East Asian
wide characters, emoji sequences, combining marks, zero-width characters and ANSI escape
sequences, measured the way a terminal draws them. Typed, zero dependencies, Unicode 18.0.0.
Install
pip install cellstr
Usage
len, slicing and str.ljust count code points, so they misalign any text that carries
colour codes, CJK characters, emoji or accents. cellstr counts display cells.
from cellstr import cell_len, cell_slice, fit, ljust, truncate
warn = "\x1b[31mWARN\x1b[0m" # red "WARN"
cell_len(warn) # -> 4
cell_len("你好") # -> 4
cell_len("👨👩👧") # -> 2
cell_len("🇯🇵") # -> 2
cell_len("é") # -> 1
cell_slice(warn, 0, 2) # -> "\x1b[31mWA\x1b[0m"
cell_slice("a你b", 0, 2) # -> "a"
cell_slice("x👨👩👧y", 0, 2) # -> "x"
ljust("你", 4) # -> "你 "
truncate("hello world", 8) # -> "hello..."
truncate("/usr/local/lib/python", 12, position="middle") # -> "/usr/...thon"
fit("张伟张伟", 5, suffix="") # -> "张伟 "
What it gets right:
- Grapheme clusters. A ZWJ family, a skin tone sequence, a flag, a keycap or a letter with accents is one unit: measured once and never split by slicing or truncation.
- Escape sequences. SGR colours, OSC 8 hyperlinks, cursor movement and the other ECMA-48 families count as nothing and are kept in place, so styled text stays styled.
- Ambiguous width. Greek, Cyrillic, box drawing and circled digits are one cell in
Western terminals and two in CJK ones. Pass
ambiguous=2to any function. - Tabs. Pass
tabsize=8to measure tab stops; slicing and padding turn tabs into the spaces they cover.expand_tabs()does it on its own. - Real Unicode data. Tables are generated by a committed script from a committed Unicode Character Database snapshot, and the full grapheme break test suite runs.
from cellstr import cell_len, iter_cells, truncate_detailed
cell_len("αβ─", ambiguous=2) # -> 6
cell_len("a\tb", tabsize=8) # -> 9
[c.width for c in iter_cells("a你🇯🇵")] # -> [1, 2, 2]
truncate_detailed("hello world", 8).truncated # -> True
Public API: cell_len, char_width, grapheme_width, iter_graphemes, iter_cells
(Cell), cell_slice, ljust, rjust, center, fit, truncate,
truncate_detailed (Truncation), expand_tabs, strip_ansi, UNICODE_VERSION, and
the Align and Position literal types. Every function is fully typed and documented.
Command line
$ printf 'abc\n你好\n' | cellstr measure
3
4
$ printf '/usr/local/lib/python3/site-packages\n' | cellstr truncate 16 --position middle
/usr/lo...ckages
$ printf 'id\n12345\n' | cellstr pad 8 --align right
id
12345
Commands: measure (--max), truncate N, pad N, fit N and slice START [STOP],
all with --ambiguous and --tabsize. cellstr --help lists runnable examples.
Terminals disagree
There is no standard for how many cells a character takes, and terminals differ on
ambiguous-width characters, emoji ZWJ sequences and variation selectors. cellstr
follows Markus Kuhn's reference wcwidth for single code points and
measures emoji sequences as one glyph, as terminals with grapheme support draw them.
GUIDE.md has the exact rules, concrete examples of where terminals differ, a
recipe for code point by code point measuring, and every difference from the wcwidth
package.
Why
wcwidth measures plain-text width well, but it does not give you a typed, cohesive set
of string operations: slicing by column that keeps escapes and graphemes intact, padding,
fitting a table cell and width-aware truncation with a suffix at either end or in the
middle. strip-ansi style tools remove escapes but know nothing about width. cellstr
does all of it in one small, fully typed, zero-dependency package.
License
MIT. See LICENSE. The property tables in src/cellstr/_ucd_*.py are generated
from the Unicode Character Database and are covered by the Unicode License v3, see LICENSE-UNICODE.
Links
- Website: https://lianes8studio.com
- GitHub: https://github.com/JaviLianes8
- LinkedIn: https://www.linkedin.com/in/jlianes/
Metadata
Release files for cellstr 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cellstr-0.2.1.tar.gz | 42.0 kB | Without provenance | Details for cellstr-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cellstr-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for cellstr-0.2.1-py3-none-any.whl |
Total release size: 66.6 kB
Release files / cellstr-0.2.1.tar.gz
| Download URL | cellstr-0.2.1.tar.gz |
|---|---|
| Size | 42.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c96f5efa3270f11a0d5c5c11cb6af80ed7eb6cfe4b39b4caf6862230daea95f8
|
|
BLAKE2b-256 checksum How to use checksums |
998ce7a207993c4f9a65484afb068abc76cae3c417f0f521afd38cf8328b76d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.2
|
Release files / cellstr-0.2.1-py3-none-any.whl
| Download URL | cellstr-0.2.1-py3-none-any.whl |
|---|---|
| Size | 24.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6fafe5adfa054f6296af9a72c21403cb04cebebf803ebcfb2ba0c9543f8c45f1
|
|
BLAKE2b-256 checksum How to use checksums |
10c965908579ca8d03b310c513d84898f7be1563ff80958f931c3574a7238e67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.2
|
Security for cellstr 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.