A portable/cross-platform implementation of wcwidth(3) with up-to-date Unicode spec.
This project has own Unicode data tables generated from following files.
- https://unicode.org/Public/17.0.0/ucd/UnicodeData.txt
- https://unicode.org/Public/17.0.0/ucd/EastAsianWidth.txt
Instead of this library, there's wcwidth imported with import Darwin, import Musl, or import Glibc.
- https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/wcwidth.3.html
- https://www.gnu.org/software/gnulib/manual/html_node/wcwidth.html
- https://git.musl-libc.org/cgit/musl/tree/src/ctype/wcwidth.c
If that meets your requirements, you should just use it. However, this project has following superior points.
- Portable/Cross-platform implementation that doesn't require a C library nor even Foundation
- Up-to-date Unicode spec
- Better support of Unicode grapheme clusters
- Swift-friendly API
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/ainame/swift-displaywidth", from: "0.1.0")
]Then:
import DisplayWidth
// call as function
let baseDisplayWidth = DisplayWidth()
baseDisplayWidth("A") // 1
baseDisplayWidth("あ") // 2
baseDisplayWidth("👩💻") // 2
baseDisplayWidth("e\u{0301}") // 1 (e + combining acute)
// If your environment treat ambiguous chars as full-width,
// you can set this option.
let ambiguousWidth = DisplayWidth(treatAmbiguousAsFullWidth: true)import DisplayWidth
// ANSI escape sequences can be ignored during string measurement.
let ansiAwareDisplayWidth = DisplayWidth(stripsANSI: true)
ansiAwareDisplayWidth("\u{001B}[31mhello\u{001B}[0m") // 5
// Tabs can advance to the next tab stop every 4 columns.
let tabStopsDisplayWidth = DisplayWidth(tab: .tabStops(4))
tabStopsDisplayWidth("a\tb") // 5
// Or each tab can count as a fixed number of spaces.
let fixedTabsDisplayWidth = DisplayWidth(tab: .fixedSpaces(3))
fixedTabsDisplayWidth("a\tb") // 5stripsANSI and tab affect string measurement only. Character and scalar
measurement keep their existing behavior. DisplayWidth.Tab.tabStops(n) uses
terminal-style tab stops, while .fixedSpaces(n) counts each tab as exactly n
columns. For example, with 3, "a\tb" is width 4 with .tabStops(3) and
width 5 with .fixedSpaces(3).
Diagram with 4:
.tabStops(4)
tab stops: 4, 8, 12, ...
"a\tb" = 1 + 3 + 1 = 5
"ab\tb" = 2 + 2 + 1 = 5
"abcd\tb" = 4 + 4 + 1 = 9
.fixedSpaces(4)
every tab = 4
"a\tb" = 1 + 4 + 1 = 6
"ab\tb" = 2 + 4 + 1 = 7
"abcd\tb" = 4 + 4 + 1 = 9
Reference: Tab stop
- https://man7.org/linux/man-pages/man3/wcwidth.3.html
- Other langs
- https://emonkak.pages.dev/articles/wcwidth/
- This project (to avoid using
wcwidth(3)) is against to this blog post but I took ideas around full-width symbols
- This project (to avoid using