Sie können es RuneCountInString
aus dem utf8-Paket versuchen .
gibt die Anzahl der Runen in p zurück
das, wie in diesem Skript dargestellt : Die Länge von "Welt" könnte 6 sein (wenn auf Chinesisch geschrieben: "世界"), aber seine Runenzahl ist 2:
package main
import "fmt"
import "unicode/utf8"
func main() {
fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界"))
}
Phrozen fügt in den Kommentaren hinzu :
Eigentlich kannst du len()
Runen übergehen, indem du einfach Casting tippst.
len([]rune("世界"))
wird gedruckt 2
. Bei Leats in Go 1.3.
Und mit CL 108985 (Mai 2018, für Go 1.11) len([]rune(string))
ist jetzt optimiert. ( Behebt das Problem 24923 )
Der Compiler erkennt das len([]rune(string))
Muster automatisch und ersetzt es durch den Aufruf von r: = range s.
Fügt eine neue Laufzeitfunktion hinzu, um Runen in einer Zeichenfolge zu zählen. Ändert den Compiler, um das Muster zu erkennen, len([]rune(string))
und ersetzt es durch die neue Laufzeitfunktion zur Runenzählung.
RuneCount/lenruneslice/ASCII 27.8ns ± 2% 14.5ns ± 3% -47.70% (p=0.000 n=10+10)
RuneCount/lenruneslice/Japanese 126ns ± 2% 60ns ± 2% -52.03% (p=0.000 n=10+10)
RuneCount/lenruneslice/MixedLength 104ns ± 2% 50ns ± 1% -51.71% (p=0.000 n=10+9)
Stefan Steiger verweist auf den Blogbeitrag " Textnormalisierung in Go "
Was ist ein Charakter?
Wie im Blog-Beitrag zu Strings erwähnt , können Charaktere mehrere Runen umfassen .
Zum Beispiel können ein ' e
' und '◌́◌́' (akut "\ u0301") kombiniert werden, um 'é' (" e\u0301
" in NFD) zu bilden. Zusammen bilden diese beiden Runen einen Charakter .
Die Definition eines Zeichens kann je nach Anwendung variieren.
Zur Normalisierung definieren wir es als:
- eine Folge von Runen, die mit einem Starter beginnt,
- eine Rune, die sich mit keiner anderen Rune ändert oder rückwärts kombiniert,
- gefolgt von einer möglicherweise leeren Folge von Nicht-Startern, dh Runen, die dies tun (normalerweise Akzente).
Der Normalisierungsalgorithmus verarbeitet jeweils ein Zeichen.
Unter Verwendung dieses Pakets und seines Iter
Typs wäre die tatsächliche Anzahl von "Zeichen":
package main
import "fmt"
import "golang.org/x/text/unicode/norm"
func main() {
var ia norm.Iter
ia.InitString(norm.NFKD, "école")
nc := 0
for !ia.Done() {
nc = nc + 1
ia.Next()
}
fmt.Printf("Number of chars: %d\n", nc)
}
Hier wird das Unicode-Normalisierungsformular NFKD "Compatibility Decomposition" verwendet.
Oliver ‚s Antwort verweist auf UNICODE TEXT SEGMENTATION als der einzige Weg , um zuverlässig Standard Grenzen zwischen bestimmten wesentlichen Textelemente zu bestimmen: Benutzer wahrgenommenen Zeichen, Wörter und Sätze.
Dafür benötigen Sie eine externe Bibliothek wie rivo / uniseg , die die Unicode-Textsegmentierung durchführt .
Das wird zählen eigentlich „ Graphem - Cluster “, in denen mehrere Codepunkte können in einem benutzer wahrgenommen Charakter kombiniert werden.
package uniseg
import (
"fmt"
"github.com/rivo/uniseg"
)
func main() {
gr := uniseg.NewGraphemes("👍🏼!")
for gr.Next() {
fmt.Printf("%x ", gr.Runes())
}
// Output: [1f44d 1f3fc] [21]
}
Zwei Grapheme, obwohl es drei Runen gibt (Unicode-Codepunkte).
Weitere Beispiele finden Sie unter " Wie manipuliere ich Zeichenfolgen in GO, um sie umzukehren? "
👩🏾🦰 allein ist ein Graphem, aber vom Unicode- zum Codepunktkonverter 4 Runen: