Extraer subcadenas en Go

114

Estoy tratando de leer una línea completa de la consola (incluidos los espacios en blanco) y luego procesarla. Usando bufio.ReadString, el carácter de nueva línea se lee junto con la entrada, así que se me ocurrió el siguiente código para recortar el carácter de nueva línea:

input,_:=src.ReadString('\n')
inputFmt:=input[0:len(input)-2]+"" //Need to manually add end of string

¿Hay alguna forma más idiomática de hacer esto? Es decir, ¿existe ya una biblioteca que se encargue del byte nulo final al extraer subcadenas por usted?

(Sí, sé que ya hay una forma de leer una línea sin el carácter de nueva línea en ir readline -> cadena, pero estoy buscando más una manipulación elegante de cadenas).

mark2222
fuente

Respuestas:

146

Parece que está confundido por el funcionamiento de los cortes y el formato de almacenamiento de cadenas, que es diferente de lo que tiene en C.

  • cualquier segmento en Go almacena la longitud (en bytes), por lo que no tiene que preocuparse por el costo de la lenoperación: no es necesario contar
  • Las cadenas Go no tienen terminación nula, por lo que no tiene que eliminar un byte nulo y no tiene que agregar 1después de cortar agregando una cadena vacía.

Para eliminar el último carácter (si es un carácter de un byte), simplemente haga

inputFmt:=input[:len(input)-1]
Denys Séguret
fuente
11
Ni siquiera necesitas el 0 (o el :), s = s[:len(s)-1]bastará.
uriel
1
Muchas gracias por aclarar; parece que había dos caracteres de espacio en blanco al final de la cadena devuelta por la función ReadString, así que confundí uno con un byte nulo. Perdón por la confusión con las cadenas de C; Estaba usando fmt junto con bufio, lo que provocó que aparecieran cosas divertidas en la consola, así que pensé que podría ser el byte nulo sucio. Solo una aclaración final: ¿cuál podría ser ese espacio en blanco adicional de ReadString?
mark2222
Ok, responderé mi propia pregunta - es \ r entonces \ n: P La salida divertida de la consola fue porque emití \ r sin \ n.
mark2222
8
Tenga en cuenta que este método no funcionará con cadenas Unicode. groups.google.com/forum/#!msg/golang-nuts/ZeYei0IWrLg/…
Melllvar
@Melllvar Es por eso que precisé "si es un carácter de un byte" . Si desea eliminar un carácter que ocupa más de un byte (ese no es el caso de OP), debe adaptarse.
Denys Séguret
25

Las cadenas de Go no tienen terminación nula, y para eliminar el último carácter de una cadena, simplemente puede hacer:

s = s[:len(s)-1]
uriel
fuente
10
Esto es incorrecto y provocará errores. Esto quita el último byte de la cadena, lo que puede invalidarla en UTF-8 (u otra codificación multibyte).
dr. Sybren
3
Consulte play.golang.org/p/K3HBBtj4Oi para ver un ejemplo de cómo se rompe esto.
dr. Sybren
10

Para evitar un pánico en una entrada de longitud cero, envuelva la operación de truncar en un if

input, _ := src.ReadString('\n')
var inputFmt string
if len(input) > 0 {
    inputFmt = input[:len(input)-1]
}
// Do something with inputFmt
Rohanthewiz
fuente
9

Este es el sencillo para realizar subcadenas en Go

package main

import "fmt"

var p = fmt.Println

func main() {

  value := "address;bar"

  // Take substring from index 2 to length of string
  substring := value[2:len(value)]
  p(substring)

}
Faris Rayhan
fuente
7

ADVERTENCIA: operar solo con cadenas solo funcionará con ASCII y contará incorrectamente cuando la entrada sea un carácter codificado no ASCII UTF-8, y probablemente incluso corromperá los caracteres ya que corta caracteres multibyte en la mitad de la secuencia.

Aquí hay una versión compatible con UTF-8:

func substr(input string, start int, length int) string {
    asRunes := []rune(input)

    if start >= len(asRunes) {
        return ""
    }

    if start+length > len(asRunes) {
        length = len(asRunes) - start
    }

    return string(asRunes[start : start+length])
}
joonas.fi
fuente
1
Esto necesita muchos más votos positivos: me mordieron mucho al no usar la división consciente de utf-8.
kolaente
2

8 años después me topé con esta joya y, sin embargo, no creo que la pregunta original de OP haya sido realmente respondida:

así que se me ocurrió el siguiente código para recortar el carácter de nueva línea

Si bien el bufio.Readertipo admite un ReadLine() método que elimina \r\ny \nestá destinado a ser una función de bajo nivel que es incómoda de usar porque son necesarias comprobaciones repetidas.

En mi opinión, una forma idiomática de eliminar los espacios en blanco es usar la biblioteca de cadenas de Golang :

input, _ = src.ReadString('\n')

// more specific to the problem of trailing newlines
actual = strings.TrimRight(input, "\r\n")

// or if you don't mind to trim leading and trailing whitespaces 
actual := strings.TrimSpace(input)

Vea este ejemplo en acción en el patio de juegos de Golang: https://play.golang.org/p/HrOWH0kl3Ww

Philipp Pixel
fuente