Package uniseg
Package uniseg implements Unicode Text Segmentation, Unicode Line Breaking, and
string width calculation for monospace fonts. Unicode Text Segmentation conforms
to Unicode Standard Annex #29 (https://unicode.org/reports/tr29/) and Unicode
Line Breaking conforms to Unicode Standard Annex #14
(https://unicode.org/reports/tr14/).
In short, using this package, you can split a string into grapheme clusters
(what people would usually refer to as a "character"), into words, and into
sentences. Or, in its simplest case, this package allows you to count the number
of characters in a string, especially when it contains complex characters such
as emojis, combining characters, or characters from Asian, Arabic, Hebrew, or
other languages. Additionally, you can use it to implement line breaking (or
"word wrapping"), that is, to determine where text can be broken over to the
next line when the width of the line is not big enough to fit the entire text.
Finally, you can use it to calculate the display width of a string for monospace
fonts.
Getting Started
If you just want to count the number of characters in a string, you can use
GraphemeClusterCount. If you want to determine the display width of a string,
you can use StringWidth. If you want to iterate over a string, you can use
Step, StepString, or the Graphemes class (more convenient but less
performant). This will provide you with all information: grapheme clusters,
word boundaries, sentence boundaries, line breaks, and monospace character
widths. The specialized functions FirstGraphemeCluster,
FirstGraphemeClusterInString, FirstWord, FirstWordInString,
FirstSentence, and FirstSentenceInString can be used if only one type of
information is needed.
Grapheme Clusters
Consider the rainbow flag emoji: π³οΈβπ. On most modern systems, it appears as one
character. But its string representation actually has 14 bytes, so counting
bytes (or using len("π³οΈβπ")) will not work as expected. Counting runes won't,
either: The flag has 4 Unicode code points, thus 4 runes. The stdlib function
utf8.RuneCountInString("π³οΈβπ") and len([]rune("π³οΈβπ")) will both return 4.
The GraphemeClusterCount function will return 1 for the rainbow flag emoji.
The Graphemes class and a variety of functions in this package will allow you to
split strings into its grapheme clusters.
Word Boundaries
Word boundaries are used in a number of different contexts. The most familiar
ones are selection (double-click mouse selection), cursor movement ("move to
next word" control-arrow keys), and the dialog option "Whole Word Search" for
search and replace. This package provides methods for determining word
boundaries.
Sentence Boundaries
Sentence boundaries are often used for triple-click or some other method of
selecting or iterating through blocks of text that are larger than single words.
They are also used to determine whether words occur within the same sentence in
database queries. This package provides methods for determining sentence
boundaries.
Line Breaking
Line breaking, also known as word wrapping, is the process of breaking a section
of text into lines such that it will fit in the available width of a page,
window or other display area. This package provides methods to determine the
positions in a string where a line must be broken, may be broken, or must not be
broken.
Monospace Width
Monospace width, as referred to in this package, is the width of a string in a
monospace font. This is commonly used in terminal user interfaces or text
displays or editors that don't support proportional fonts. A width of 1
corresponds to a single character cell. The C function wcswidth() and its
implementation in other programming languages is in widespread use for the same
purpose. However, there is no standard for the calculation of such widths, and
this package differs from wcswidth() in a number of ways, presumably to generate
more visually pleasing results.
To start, we assume that every code point has a width of 1, with the following
exceptions:
- Code points with grapheme cluster break properties Control, CR, LF, Extend,
and ZWJ have a width of 0.
- U+2E3A, Two-Em Dash, has a width of 3.
- U+2E3B, Three-Em Dash, has a width of 4.
- Characters with the East-Asian Width properties "Fullwidth" (F) and "Wide"
(W) have a width of 2. (Properties "Ambiguous" (A) and "Neutral" (N) both
have a width of 1.)
- Code points with grapheme cluster break property Regional Indicator have a
width of 2.
- Code points with grapheme cluster break property Extended Pictographic have
a width of 2, unless their Emoji Presentation flag is "No", in which case
the width is 1.
For Hangul grapheme clusters composed of conjoining Jamo and for Regional
Indicators (flags), all code points except the first one have a width of 0. For
grapheme clusters starting with an Extended Pictographic, any additional code
point will force a total width of 2, except if the Variation Selector-15
(U+FE0E) is included, in which case the total width is always 1. Grapheme
clusters ending with Variation Selector-16 (U+FE0F) have a width of 2.
Note that whether these widths appear correct depends on your application's
render engine, to which extent it conforms to the Unicode Standard, and its
choice of font.
- Constants
- Variables
- func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int)
- func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, width, newState int)
- func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int)
- func FirstLineSegmentInString(str string, state int) (segment, rest string, mustBreak bool, newState int)
- func FirstSentence(b []byte, state int) (sentence, rest []byte, newState int)
- func FirstSentenceInString(str string, state int) (sentence, rest string, newState int)
- func FirstWord(b []byte, state int) (word, rest []byte, newState int)
- func FirstWordInString(str string, state int) (word, rest string, newState int)
- func GraphemeClusterCount(s string) (n int)
- func HasTrailingLineBreak(b []byte) bool
- func HasTrailingLineBreakInString(str string) bool
- func ReverseString(s string) string
- func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState int)
- func StepString(str string, state int) (cluster, rest string, boundaries int, newState int)
- func StringWidth(s string) (width int)
- type Graphemes
- func NewGraphemes(str string) *Graphemes
- func (g *Graphemes) Bytes() []byte
- func (g *Graphemes) IsSentenceBoundary() bool
- func (g *Graphemes) IsWordBoundary() bool
- func (g *Graphemes) LineBreak() int
- func (g *Graphemes) Next() bool
- func (g *Graphemes) Positions() (int, int)
- func (g *Graphemes) Reset()
- func (g *Graphemes) Runes() []rune
- func (g *Graphemes) Str() string
- func (g *Graphemes) Width() int
Package files
doc.go
eastasianwidth.go
emojipresentation.go
grapheme.go
graphemeproperties.go
graphemerules.go
line.go
lineproperties.go
linerules.go
properties.go
sentence.go
sentenceproperties.go
sentencerules.go
step.go
width.go
word.go
wordproperties.go
wordrules.go
Constants
These constants define whether a given text may be broken into the next line.
If the break is optional (LineCanBreak), you may choose to break or not based
on your own criteria, for example, if the text has reached the available
width.
const (
LineDontBreak = iota
LineCanBreak
LineMustBreak
)
The bit masks used to extract boundary information returned by Step.
const (
MaskLine = 3
MaskWord = 4
MaskSentence = 8
)
The number of bits to shift the boundary information returned by Step to
obtain the monospace width of the grapheme cluster.
const ShiftWidth = 4
Variables
EastAsianAmbiguousWidth specifies the monospace width for East Asian
characters classified as Ambiguous. The default is 1 but some rare fonts
render them with a width of 2.
var EastAsianAmbiguousWidth = 1
func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int)
FirstGraphemeCluster returns the first grapheme cluster found in the given
byte slice according to the rules of Unicode Standard Annex #29, Grapheme
Cluster Boundaries. This function can be called continuously to extract all
grapheme clusters from a byte slice, as illustrated in the example below.
If you don't know the current state, for example when calling the function
for the first time, you must pass -1. For consecutive calls, pass the state
and rest slice returned by the previous call.
The "rest" slice is the sub-slice of the original byte slice "b" starting
after the last byte of the identified grapheme cluster. If the length of the
"rest" slice is 0, the entire byte slice "b" has been processed. The
"cluster" byte slice is the sub-slice of the input slice containing the
identified grapheme cluster.
The returned width is the width of the grapheme cluster for most monospace
fonts where a value of 1 represents one character cell.
Given an empty byte slice "b", the function returns nil values.
While slightly less convenient than using the Graphemes class, this function
has much better performance and makes no allocations. It lends itself well to
large byte slices.
βΎ Example
Code:
b := []byte("π©πͺπ³οΈβπ!")
state := -1
var c []byte
for len(b) > 0 {
var width int
c, b, width, state = uniseg.FirstGraphemeCluster(b, state)
fmt.Println(string(c), width)
}
Output:
π©πͺ 2
π³οΈβπ 2
! 1
func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, width, newState int)
FirstGraphemeClusterInString is like FirstGraphemeCluster but its input and
outputs are strings.
βΎ Example
Code:
str := "π©πͺπ³οΈβπ!"
state := -1
var c string
for len(str) > 0 {
var width int
c, str, width, state = uniseg.FirstGraphemeClusterInString(str, state)
fmt.Println(c, width)
}
Output:
π©πͺ 2
π³οΈβπ 2
! 1
func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int)
FirstLineSegment returns the prefix of the given byte slice after which a
decision to break the string over to the next line can or must be made,
according to the rules of Unicode Standard Annex #14. This is used to
implement line breaking.
Line breaking, also known as word wrapping, is the process of breaking a
section of text into lines such that it will fit in the available width of a
page, window or other display area.
The returned "segment" may not be broken into smaller parts, unless no other
breaking opportunities present themselves, in which case you may break by
grapheme clusters (using the FirstGraphemeCluster function to determine the
grapheme clusters).
The "mustBreak" flag indicates whether you MUST break the line after the
given segment (true), for example after newline characters, or you MAY break
the line after the given segment (false).
This function can be called continuously to extract all non-breaking sub-sets
from a byte slice, as illustrated in the example below.
If you don't know the current state, for example when calling the function
for the first time, you must pass -1. For consecutive calls, pass the state
and rest slice returned by the previous call.
The "rest" slice is the sub-slice of the original byte slice "b" starting
after the last byte of the identified line segment. If the length of the
"rest" slice is 0, the entire byte slice "b" has been processed. The
"segment" byte slice is the sub-slice of the input slice containing the
identified line segment.
Given an empty byte slice "b", the function returns nil values.
Note that in accordance with UAX #14 LB3, the final segment will end with
"mustBreak" set to true. You can choose to ignore this by checking if the
length of the "rest" slice is 0 and calling HasTrailingLineBreak or
HasTrailingLineBreakInString on the last rune.
Note also that this algorithm may break within grapheme clusters. This is
addressed in Section 8.2 Example 6 of UAX #14. To avoid this, you can use
the Step function instead.
βΎ Example
Code:
b := []byte("First line.\nSecond line.")
state := -1
var (
c []byte
mustBreak bool
)
for len(b) > 0 {
c, b, mustBreak, state = uniseg.FirstLineSegment(b, state)
fmt.Printf("(%s)", string(c))
if mustBreak {
fmt.Print("!")
}
}
Output:
(First )(line.
)!(Second )(line.)!
func FirstLineSegmentInString(str string, state int) (segment, rest string, mustBreak bool, newState int)
FirstLineSegmentInString is like FirstLineSegment but its input and outputs
are strings.
βΎ Example
Code:
str := "First line.\nSecond line."
state := -1
var (
c string
mustBreak bool
)
for len(str) > 0 {
c, str, mustBreak, state = uniseg.FirstLineSegmentInString(str, state)
fmt.Printf("(%s)", c)
if mustBreak {
fmt.Println(" < must break")
} else {
fmt.Println(" < may break")
}
}
Output:
(First ) < may break
(line.
) < must break
(Second ) < may break
(line.) < must break
func FirstSentence(b []byte, state int) (sentence, rest []byte, newState int)
FirstSentence returns the first sentence found in the given byte slice
according to the rules of Unicode Standard Annex #29, Sentence Boundaries.
This function can be called continuously to extract all sentences from a byte
slice, as illustrated in the example below.
If you don't know the current state, for example when calling the function
for the first time, you must pass -1. For consecutive calls, pass the state
and rest slice returned by the previous call.
The "rest" slice is the sub-slice of the original byte slice "b" starting
after the last byte of the identified sentence. If the length of the "rest"
slice is 0, the entire byte slice "b" has been processed. The "sentence" byte
slice is the sub-slice of the input slice containing the identified sentence.
Given an empty byte slice "b", the function returns nil values.
βΎ Example
Code:
b := []byte("This is sentence 1.0. And this is sentence two.")
state := -1
var c []byte
for len(b) > 0 {
c, b, state = uniseg.FirstSentence(b, state)
fmt.Printf("(%s)\n", string(c))
}
Output:
(This is sentence 1.0. )
(And this is sentence two.)
func FirstSentenceInString(str string, state int) (sentence, rest string, newState int)
FirstSentenceInString is like FirstSentence but its input and outputs are
strings.
βΎ Example
Code:
str := "This is sentence 1.0. And this is sentence two."
state := -1
var c string
for len(str) > 0 {
c, str, state = uniseg.FirstSentenceInString(str, state)
fmt.Printf("(%s)\n", c)
}
Output:
(This is sentence 1.0. )
(And this is sentence two.)
func FirstWord(b []byte, state int) (word, rest []byte, newState int)
FirstWord returns the first word found in the given byte slice according to
the rules of Unicode Standard Annex #29, Word Boundaries. This function can
be called continuously to extract all words from a byte slice, as illustrated
in the example below.
If you don't know the current state, for example when calling the function
for the first time, you must pass -1. For consecutive calls, pass the state
and rest slice returned by the previous call.
The "rest" slice is the sub-slice of the original byte slice "b" starting
after the last byte of the identified word. If the length of the "rest" slice
is 0, the entire byte slice "b" has been processed. The "word" byte slice is
the sub-slice of the input slice containing the identified word.
Given an empty byte slice "b", the function returns nil values.
βΎ Example
Code:
b := []byte("Hello, world!")
state := -1
var c []byte
for len(b) > 0 {
c, b, state = uniseg.FirstWord(b, state)
fmt.Printf("(%s)\n", string(c))
}
Output:
(Hello)
(,)
( )
(world)
(!)
func FirstWordInString(str string, state int) (word, rest string, newState int)
FirstWordInString is like FirstWord but its input and outputs are strings.
βΎ Example
Code:
str := "Hello, world!"
state := -1
var c string
for len(str) > 0 {
c, str, state = uniseg.FirstWordInString(str, state)
fmt.Printf("(%s)\n", c)
}
Output:
(Hello)
(,)
( )
(world)
(!)
func GraphemeClusterCount(s string) (n int)
GraphemeClusterCount returns the number of user-perceived characters
(grapheme clusters) for the given string.
βΎ Example
Code:
n := uniseg.GraphemeClusterCount("π©πͺπ³οΈβπ")
fmt.Println(n)
Output:
2
func HasTrailingLineBreak(b []byte) bool
HasTrailingLineBreak returns true if the last rune in the given byte slice is
one of the hard line break code points defined in LB4 and LB5 of UAX #14.
func HasTrailingLineBreakInString(str string) bool
HasTrailingLineBreakInString is like HasTrailingLineBreak but for a string.
func ReverseString(s string) string
ReverseString reverses the given string while observing grapheme cluster
boundaries.
func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState int)
Step returns the first grapheme cluster (user-perceived character) found in
the given byte slice. It also returns information about the boundary between
that grapheme cluster and the one following it as well as the monospace width
of the grapheme cluster. There are three types of boundary information: word
boundaries, sentence boundaries, and line breaks. This function is therefore
a combination of FirstGraphemeCluster, FirstWord, FirstSentence, and
FirstLineSegment.
The "boundaries" return value can be evaluated as follows:
- boundaries&MaskWord != 0: The boundary is a word boundary.
- boundaries&MaskWord == 0: The boundary is not a word boundary.
- boundaries&MaskSentence != 0: The boundary is a sentence boundary.
- boundaries&MaskSentence == 0: The boundary is not a sentence boundary.
- boundaries&MaskLine == LineDontBreak: You must not break the line at the
boundary.
- boundaries&MaskLine == LineMustBreak: You must break the line at the
boundary.
- boundaries&MaskLine == LineCanBreak: You may or may not break the line at
the boundary.
- boundaries >> ShiftWidth: The width of the grapheme cluster for most
monospace fonts where a value of 1 represents one character cell.
This function can be called continuously to extract all grapheme clusters
from a byte slice, as illustrated in the examples below.
If you don't know which state to pass, for example when calling the function
for the first time, you must pass -1. For consecutive calls, pass the state
and rest slice returned by the previous call.
The "rest" slice is the sub-slice of the original byte slice "b" starting
after the last byte of the identified grapheme cluster. If the length of the
"rest" slice is 0, the entire byte slice "b" has been processed. The
"cluster" byte slice is the sub-slice of the input slice containing the
first identified grapheme cluster.
Given an empty byte slice "b", the function returns nil values.
While slightly less convenient than using the Graphemes class, this function
has much better performance and makes no allocations. It lends itself well to
large byte slices.
Note that in accordance with UAX #14 LB3, the final segment will end with
a mandatory line break (boundaries&MaskLine == LineMustBreak). You can choose
to ignore this by checking if the length of the "rest" slice is 0 and calling
HasTrailingLineBreak or HasTrailingLineBreakInString on the last rune.
βΎ Example (Graphemes)
Code:
b := []byte("π©πͺπ³οΈβπ!")
state := -1
var c []byte
for len(b) > 0 {
var boundaries int
c, b, boundaries, state = uniseg.Step(b, state)
fmt.Println(string(c), boundaries>>uniseg.ShiftWidth)
}
Output:
π©πͺ 2
π³οΈβπ 2
! 1
βΉ Example (LineBreaking)
βΎ Example (LineBreaking)
Code:
b := []byte("First line.\nSecond line.")
state := -1
var (
c []byte
boundaries int
)
for len(b) > 0 {
c, b, boundaries, state = uniseg.Step(b, state)
fmt.Print(string(c))
if boundaries&uniseg.MaskLine == uniseg.LineCanBreak {
fmt.Print("|")
} else if boundaries&uniseg.MaskLine == uniseg.LineMustBreak {
fmt.Print("β")
}
}
Output:
First |line.
βSecond |line.β
βΎ Example (Sentence)
Code:
b := []byte("This is sentence 1.0. And this is sentence two.")
state := -1
var (
c []byte
boundaries int
)
for len(b) > 0 {
c, b, boundaries, state = uniseg.Step(b, state)
fmt.Print(string(c))
if boundaries&uniseg.MaskSentence != 0 {
fmt.Print("|")
}
}
Output:
This is sentence 1.0. |And this is sentence two.|
βΎ Example (Word)
Code:
b := []byte("Hello, world!")
state := -1
var (
c []byte
boundaries int
)
for len(b) > 0 {
c, b, boundaries, state = uniseg.Step(b, state)
fmt.Print(string(c))
if boundaries&uniseg.MaskWord != 0 {
fmt.Print("|")
}
}
Output:
Hello|,| |world|!|
func StepString(str string, state int) (cluster, rest string, boundaries int, newState int)
StepString is like Step but its input and outputs are strings.
βΎ Example (Graphemes)
Code:
str := "π©πͺπ³οΈβπ!"
state := -1
var c string
for len(str) > 0 {
var boundaries int
c, str, boundaries, state = uniseg.StepString(str, state)
fmt.Println(c, boundaries>>uniseg.ShiftWidth)
}
Output:
π©πͺ 2
π³οΈβπ 2
! 1
βΉ Example (LineBreaking)
βΎ Example (LineBreaking)
Code:
str := "First line.\nSecond line."
state := -1
var (
c string
boundaries int
)
for len(str) > 0 {
c, str, boundaries, state = uniseg.StepString(str, state)
fmt.Print(c)
if boundaries&uniseg.MaskLine == uniseg.LineCanBreak {
fmt.Print("|")
} else if boundaries&uniseg.MaskLine == uniseg.LineMustBreak {
fmt.Print("β")
}
}
Output:
First |line.
βSecond |line.β
βΎ Example (Sentence)
Code:
str := "This is sentence 1.0. And this is sentence two."
state := -1
var (
c string
boundaries int
)
for len(str) > 0 {
c, str, boundaries, state = uniseg.StepString(str, state)
fmt.Print(c)
if boundaries&uniseg.MaskSentence != 0 {
fmt.Print("|")
}
}
Output:
This is sentence 1.0. |And this is sentence two.|
βΎ Example (Word)
Code:
str := "Hello, world!"
state := -1
var (
c string
boundaries int
)
for len(str) > 0 {
c, str, boundaries, state = uniseg.StepString(str, state)
fmt.Print(c)
if boundaries&uniseg.MaskWord != 0 {
fmt.Print("|")
}
}
Output:
Hello|,| |world|!|
func StringWidth(s string) (width int)
StringWidth returns the monospace width for the given string, that is, the
number of same-size cells to be occupied by the string.
βΎ Example
Code:
fmt.Println(uniseg.StringWidth("Hello, δΈη"))
Output:
11
Graphemes implements an iterator over Unicode grapheme clusters, or
user-perceived characters. While iterating, it also provides information
about word boundaries, sentence boundaries, line breaks, and monospace
character widths.
After constructing the class via NewGraphemes for a given string "str",
Graphemes.Next is called for every grapheme cluster in a loop until it
returns false. Inside the loop, information about the grapheme cluster as
well as boundary information and character width is available via the various
methods (see examples below).
This class basically wraps the StepString parser and provides a convenient
interface to it. If you are only interested in some parts of this package's
functionality, using the specialized functions starting with "First" is
almost always faster.
type Graphemes struct {
}
βΎ Example (Graphemes)
Code:
g := uniseg.NewGraphemes("π©πͺπ³οΈβπ")
for g.Next() {
fmt.Println(g.Str())
}
Output:
π©πͺ
π³οΈβπ
βΉ Example (LineBreaking)
βΎ Example (LineBreaking)
Code:
g := uniseg.NewGraphemes("First line.\nSecond line.")
for g.Next() {
fmt.Print(g.Str())
if g.LineBreak() == uniseg.LineCanBreak {
fmt.Print("|")
} else if g.LineBreak() == uniseg.LineMustBreak {
fmt.Print("β")
}
}
if g.LineBreak() == uniseg.LineMustBreak {
fmt.Print("\nNo clusters left. LineMustBreak")
}
g.Reset()
if g.LineBreak() == uniseg.LineDontBreak {
fmt.Print("\nIterator has been reset. LineDontBreak")
}
Output:
First |line.
βSecond |line.β
No clusters left. LineMustBreak
Iterator has been reset. LineDontBreak
βΎ Example (Sentence)
Code:
g := uniseg.NewGraphemes("This is sentence 1.0. And this is sentence two.")
for g.Next() {
fmt.Print(g.Str())
if g.IsSentenceBoundary() {
fmt.Print("|")
}
}
Output:
This is sentence 1.0. |And this is sentence two.|
βΎ Example (Word)
Code:
g := uniseg.NewGraphemes("Hello, world!")
for g.Next() {
fmt.Print(g.Str())
if g.IsWordBoundary() {
fmt.Print("|")
}
}
Output:
Hello|,| |world|!|
func NewGraphemes(str string) *Graphemes
NewGraphemes returns a new grapheme cluster iterator.
func (*Graphemes) Bytes
¶
func (g *Graphemes) Bytes() []byte
Bytes returns a byte slice which corresponds to the current grapheme cluster.
If the iterator is already past the end or Graphemes.Next has not yet been
called, nil is returned.
func (g *Graphemes) IsSentenceBoundary() bool
IsSentenceBoundary returns true if a sentence ends after the current
grapheme cluster.
func (g *Graphemes) IsWordBoundary() bool
IsWordBoundary returns true if a word ends after the current grapheme
cluster.
func (g *Graphemes) LineBreak() int
LineBreak returns whether the line can be broken after the current grapheme
cluster. A value of LineDontBreak means the line may not be broken, a value
of LineMustBreak means the line must be broken, and a value of
LineCanBreak means the line may or may not be broken.
func (*Graphemes) Next
¶
func (g *Graphemes) Next() bool
Next advances the iterator by one grapheme cluster and returns false if no
clusters are left. This function must be called before the first cluster is
accessed.
func (g *Graphemes) Positions() (int, int)
Positions returns the interval of the current grapheme cluster as byte
positions into the original string. The first returned value "from" indexes
the first byte and the second returned value "to" indexes the first byte that
is not included anymore, i.e. str[from:to] is the current grapheme cluster of
the original string "str". If Graphemes.Next has not yet been called, both
values are 0. If the iterator is already past the end, both values are 1.
func (*Graphemes) Reset
¶
func (g *Graphemes) Reset()
Reset puts the iterator into its initial state such that the next call to
Graphemes.Next sets it to the first grapheme cluster again.
func (*Graphemes) Runes
¶
func (g *Graphemes) Runes() []rune
Runes returns a slice of runes (code points) which corresponds to the current
grapheme cluster. If the iterator is already past the end or Graphemes.Next
has not yet been called, nil is returned.
func (*Graphemes) Str
¶
func (g *Graphemes) Str() string
Str returns a substring of the original string which corresponds to the
current grapheme cluster. If the iterator is already past the end or
Graphemes.Next has not yet been called, an empty string is returned.
func (*Graphemes) Width
¶
func (g *Graphemes) Width() int
Width returns the monospace width of the current grapheme cluster.