string - remove - ¿Cómo obtener el número de caracteres en una cadena?
strip_tags php ejemplo (4)
Depende mucho de tu definición de lo que es un "personaje". Si "rune es igual a un personaje" está bien para su tarea (generalmente no lo es), entonces la respuesta de VonC es perfecta para usted. De lo contrario, probablemente debería observarse que hay pocas situaciones en las que el número de runas en una cadena Unicode sea un valor interesante. E incluso en esas situaciones, es mejor, si es posible, inferir el conteo al "atravesar" la cadena a medida que se procesan las runas para evitar doblar el esfuerzo de descodificación UTF-8.
¿Cómo puedo obtener la cantidad de caracteres de una cadena en Go?
Por ejemplo, si tengo una cadena "hello"
el método debe devolver 5
. Vi que len(str)
devuelve el número de bytes y no el número de caracteres, de modo que len("£")
devuelve 2 en lugar de 1 porque £ está codificado con dos bytes en UTF-8.
Hay una forma de obtener el recuento de runas sin ningún paquete convirtiendo string a [] rune como len([]rune(YOUR_STRING))
:
package main
import "fmt"
func main() {
russian := "Спутник и погром"
english := "Sputnik & pogrom"
fmt.Println("count of bytes:",
len(russian),
len(english))
fmt.Println("count of runes:",
len([]rune(russian)),
len([]rune(english)))
}
recuento de bytes 30 16
recuento de runas 16 16
Puede probar RuneCountInString
desde el paquete utf8.
devuelve la cantidad de runas en p
eso, como se ilustra en este guión : la longitud de "Mundo" podría ser 6 (cuando está escrito en chino: "世界"), pero su recuento de runa es 2:
package main
import "fmt"
import "unicode/utf8"
func main() {
fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界"))
}
Phrozen agrega en los comentarios :
De hecho, puedes hacer len()
sobre runas simplemente escribiendo hechizo.
len([]rune("世界"))
imprimirá 2
. En leats en Go 1.3.
Y con CL 108985 (mayo de 2018, para Go 1.11), len([]rune(string))
ahora está optimizado. ( Soluciona el problema 24923 )
El compilador detecta automáticamente el patrón len([]rune(string))
y lo reemplaza por r: = llamada de rango.
Agrega una nueva función de tiempo de ejecución para contar runas en una cadena. Modifica el compilador para detectar el patrón
len([]rune(string))
y lo reemplaza con la nueva función runtime de runa.
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 señala la entrada del blog " Normalización de texto en Go "
¿Qué es un personaje?
Como se mencionó en la publicación del blog de cadenas , los personajes pueden abarcar múltiples runas .
Por ejemplo, una ''e
'' y ''◌◌'' (aguda "/ u0301") pueden combinarse para formar ''é'' ("e/u0301
" en NFD). Juntos, estas dos runas son un personaje .La definición de un personaje puede variar según la aplicación.
Para la normalization lo definiremos como:
- una secuencia de runas que comienza con un starter,
- una runa que no se modifica ni se combina hacia atrás con ninguna otra runa,
- seguido de una secuencia posiblemente vacía de no iniciadores, es decir, runas que sí lo hacen (típicamente acentos).
El algoritmo de normalización procesa un carácter a la vez.
Usando ese paquete y su tipo de Iter
, el número real de "caracteres" sería:
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)
}
Aquí, utiliza el formulario de normalización Unicode NFKD "Descomposición de compatibilidad"
Si necesita tomar en cuenta los clústeres de grafemas, use el módulo regexp o unicode. También es necesario contar el número de puntos de código (runas) o bytes para la validación, ya que la longitud del cluster de grafemas es ilimitada. Si desea eliminar secuencias extremadamente largas, verifique si las secuencias se ajustan al formato de texto seguro .
package main
import (
"regexp"
"unicode"
"strings"
)
func main() {
str := "/u0308" + "a/u0308" + "o/u0308" + "u/u0308"
str2 := "a" + strings.Repeat("/u0308", 1000)
println(4 == GraphemeCountInString(str))
println(4 == GraphemeCountInString2(str))
println(1 == GraphemeCountInString(str2))
println(1 == GraphemeCountInString2(str2))
println(true == IsStreamSafeString(str))
println(false == IsStreamSafeString(str2))
}
func GraphemeCountInString(str string) int {
re := regexp.MustCompile("//PM//pM*|.")
return len(re.FindAllString(str, -1))
}
func GraphemeCountInString2(str string) int {
length := 0
checked := false
index := 0
for _, c := range str {
if !unicode.Is(unicode.M, c) {
length++
if checked == false {
checked = true
}
} else if checked == false {
length++
}
index++
}
return length
}
func IsStreamSafeString(str string) bool {
re := regexp.MustCompile("//PM//pM{30,}")
return !re.MatchString(str)
}