# string-width
[](https://crates.io/crates/string-width)
[](https://docs.rs/string-width)
[](https://github.com/sabry-awad97/string-width#license)
[](https://github.com/sabry-awad97/string-width/actions)
Accurate Unicode string width calculation for terminal applications. This library correctly handles:
- **Emoji sequences** (π¨βπ©βπ§βπ¦, πΊπΈ, 1οΈβ£)
- **East Asian characters** (δ½ ε₯½, γγγ«γ‘γ―, μλ
νμΈμ)
- **Combining marks and diacritics** (Γ©, Γ±, ΓΌ)
- **Zero-width characters** (ZWJ, ZWNJ, format characters)
- **ANSI escape sequences** (colors, cursor movement)
- **Ambiguous width characters** (Β±, Γ, Γ·)
## Features
- π― **Accurate**: Implements Unicode Standard recommendations for character width
- π **Fast**: Optimized for performance with minimal allocations
- π§ **Configurable**: Handle ambiguous characters and ANSI codes as needed
- π¦ **Zero-config**: Works out of the box with sensible defaults
- π§ͺ **Well-tested**: Comprehensive test suite with 160+ test cases
## Quick Start
Add this to your `Cargo.toml`:
```toml
[dependencies]
string-width = "0.1.0"
```
**Minimum Supported Rust Version (MSRV)**: 1.85
## Usage
### Basic Usage
```rust
use string_width::string_width;
// ASCII text
assert_eq!(string_width("Hello"), 5);
// East Asian characters (full-width)
assert_eq!(string_width("δ½ ε₯½"), 4);
// Emoji
assert_eq!(string_width("π"), 2);
assert_eq!(string_width("πΊπΈ"), 2); // Flag
assert_eq!(string_width("1οΈβ£"), 2); // Keycap sequence
// Mixed content
assert_eq!(string_width("Hello π δΈη"), 13);
// ANSI escape sequences are ignored by default
assert_eq!(string_width("\x1b[31mRed\x1b[0m"), 3);
```
### Advanced Configuration
```rust
use string_width::{string_width, string_width_with_options, StringWidthOptions, AmbiguousWidthTreatment};
// Direct configuration
let options = StringWidthOptions {
count_ansi: true, // Count ANSI escape sequences
ambiguous_width: AmbiguousWidthTreatment::Wide, // Treat ambiguous as wide
};
assert_eq!(string_width_with_options("Β±ΓΓ·", options.clone()), 6); // Ambiguous chars as wide
assert_eq!(string_width_with_options("\x1b[31mRed\x1b[0m", options), 12); // Count ANSI
// Using the builder pattern (recommended)
let options = StringWidthOptions::builder()
.count_ansi(true)
.ambiguous_as_wide()
.build();
assert_eq!(string_width_with_options("Β±ΓΓ·", options), 6);
```
### Configuration Builder Pattern
```rust
use string_width::{string_width, StringWidthOptions, AmbiguousWidthTreatment};
// Fluent builder API for easy configuration
let options = StringWidthOptions::builder()
.count_ansi(true)
.ambiguous_as_wide()
.build();
let text = "\x1b[31mΒ±ΓΓ·\x1b[0m";
assert_eq!(string_width((text, options)), 14); // ANSI + wide ambiguous
// Convenience methods for common configurations
let narrow_options = StringWidthOptions::builder()
.ambiguous_as_narrow()
.build();
let wide_options = StringWidthOptions::builder()
.ambiguous_as_wide()
.build();
// Equivalent to direct construction but more readable
let manual_options = StringWidthOptions {
count_ansi: true,
ambiguous_width: AmbiguousWidthTreatment::Wide,
};
```
### Using the DisplayWidth Trait
```rust
use string_width::{DisplayWidth, StringWidthOptions};
let text = "Hello π";
println!("Width: {}", text.display_width());
// With custom options using builder pattern
let options = StringWidthOptions::builder()
.count_ansi(false)
.ambiguous_as_narrow()
.build();
println!("Width: {}", text.display_width_with_options(options));
// Works with both &str and String
let owned_string = String::from("Hello π");
println!("Width: {}", owned_string.display_width());
```
## Terminal Applications
Perfect for building CLI tools that need proper text alignment:
### Text Alignment
```rust
use string_width::DisplayWidth;
fn align_text(text: &str, width: usize) -> String {
let text_width = text.display_width();
let padding = width.saturating_sub(text_width);
format!("{}{}", text, " ".repeat(padding))
}
// Works correctly with Unicode content
println!("β{}β", align_text("Hello", 10)); // βHello β
println!("β{}β", align_text("δ½ ε₯½", 10)); // βδ½ ε₯½ β
println!("β{}β", align_text("πΊπΈ USA", 10)); // βπΊπΈ USA β
```
### Table Formatting
```rust
use string_width::DisplayWidth;
let data = vec![
("Name", "Country", "Greeting"),
("Alice", "πΊπΈ USA", "Hello!"),
("η°δΈ", "π―π΅ Japan", "γγγ«γ‘γ―"),
];
// Calculate column widths
let widths: Vec<usize> = (0..3)
.map(|col| data.iter().map(|row| {
match col {
0 => row.0.display_width(),
1 => row.1.display_width(),
2 => row.2.display_width(),
_ => 0,
}
}).max().unwrap_or(0))
.collect();
// Print aligned table
for (name, country, greeting) in data {
println!("β {:width0$} β {:width1$} β {:width2$} β",
name, country, greeting,
width0 = widths[0], width1 = widths[1], width2 = widths[2]
);
}
```
## Examples
The library includes comprehensive examples demonstrating various use cases:
```bash
# Basic usage examples - demonstrates core functionality
cargo run --example basic_usage
# Terminal formatting and alignment - shows real-world usage
cargo run --example terminal_formatting
# CLI tool for measuring text width - interactive width analysis
cargo run --example cli_tool -- "Hello π World"
### Key Example Features
- **Basic Usage**: ASCII, Unicode, emoji, and mixed content width calculation
- **Terminal Formatting**: Text alignment, table formatting, and progress bars
- **CLI Tool**: Interactive analysis with detailed character breakdown and formatting examples
## Supported Unicode Features
| ASCII | `"Hello"` | 5 |
| East Asian | `"δ½ ε₯½"` | 4 |
| Emoji | `"π"` | 2 |
| Emoji sequences | `"π¨βπ©βπ§βπ¦"` | 2 |
| Keycap sequences | `"1οΈβ£"` | 2 |
| Flag sequences | `"πΊπΈ"` | 2 |
| Combining marks | `"Γ©"` (e + Β΄) | 1 |
| Zero-width chars | `"a\u{200B}b"` | 2 |
| ANSI codes | `"\x1b[31mRed\x1b[0m"` | 3 |
## Architecture
The library is designed with a modular architecture:
- **`width_calculation`**: Core width calculation logic and public API
- **`character_classification`**: Unicode character categorization and analysis
- **`emoji`**: Emoji sequence detection and handling
- **`options`**: Configuration types and builder pattern
- **`unicode_constants`**: Precomputed Unicode property tables
## Performance
The library is optimized for performance:
- Minimal allocations during width calculation
- Efficient Unicode property lookups using precomputed tables
- Compiled regex patterns for zero-width detection
- Single-pass processing for most cases
- Optimized grapheme cluster processing
## API Overview
The library provides multiple ways to calculate string width:
| `string_width()` | Simple width calculation | `string_width("Hello")` |
| `DisplayWidth` | Ergonomic trait-based API | `"Hello".display_width()` |
| `StringWidthInput` | Legacy compatibility | `"Hello".calculate_width()` |
| Builder Pattern | Complex configuration | `StringWidthOptions::builder().build()` |
## Comparison with Other Libraries
| **string-width** | β
Full | β
Yes | β
Configurable | β
Yes | β
Yes |
| unicode-width | β Basic | β
Yes | β No | β
Yes | β No |
| textwrap | β No | β
Yes | β No | β
Yes | β No |
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
## License
This project is licensed under either of
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
## Acknowledgments
- Unicode Consortium for the Unicode Standard
- East Asian Width property implementation
- Terminal emulator developers for width handling insights