Wyodrębnianie podciągów w Go


114

Próbuję odczytać cały wiersz z konsoli (w tym białe znaki), a następnie go przetworzyć. Używając bufio.ReadString, znak nowego wiersza jest odczytywany razem z wejściem, więc wymyśliłem następujący kod, aby przyciąć znak nowego wiersza:

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

Czy jest na to bardziej idiomatyczny sposób? To znaczy, czy istnieje już biblioteka, która zajmuje się końcowym bajtem zerowym podczas wyodrębniania za Ciebie podciągów?

(Tak, wiem, że istnieje już sposób na odczytanie wiersza bez znaku nowej linii w go readline -> string, ale szukam bardziej eleganckiej manipulacji na ciągach).

Odpowiedzi:


146

Wygląda na to, że jesteś zdezorientowany działaniem plasterków i formatem przechowywania ciągów, który różni się od tego, który masz w C.

  • każdy wycinek w Go przechowuje długość (w bajtach), więc nie musisz przejmować się kosztem lenoperacji: nie ma potrzeby liczyć
  • Ciągi Go nie są zakończone wartością null, więc nie musisz usuwać bajtu zerowego i nie musisz dodawać 1po wycięciu, dodając pusty ciąg.

Aby usunąć ostatni znak (jeśli jest to znak jednobajtowy), po prostu zrób

inputFmt:=input[:len(input)-1]

11
Nie potrzebujesz nawet 0 (lub :), s = s[:len(s)-1]wystarczy.
uriel

8
Należy pamiętać, że ta metoda nie będzie działać z ciągami znaków Unicode! groups.google.com/forum/#!msg/golang-nuts/ZeYei0IWrLg/…
Melllvar

@Melllvar Dlatego sprecyzowałem „jeśli jest to jednobajtowy znak” . Jeśli chcesz usunąć znak zajmujący więcej niż jeden bajt (to nie jest przypadek OP), musisz się dostosować.
Denys Séguret

25

Ciągi Go nie są zakończone wartością null, a aby usunąć ostatni znak ciągu, możesz po prostu zrobić:

s = s[:len(s)-1]

10
Jest to niepoprawne i spowoduje błędy. To usuwa ostatni bajt z ciągu, co może spowodować, że będzie on nieprawidłowy w UTF-8 (lub innym kodowaniu wielobajtowym).
dr. Sybren

3
Zobacz play.golang.org/p/K3HBBtj4Oi, aby zobaczyć, jak to się psuje.
dr. Sybren

10

Aby uniknąć paniki przy wejściach o zerowej długości, zawiń operację obcięcia za pomocą if

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

9

To jest prosty sposób na wykonanie podciągu w 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)

}

7

OSTRZEŻENIE: operowanie na samych łańcuchach będzie działać tylko z ASCII i będzie liczyć nieprawidłowo, gdy wejście jest znakiem zakodowanym w formacie innym niż ASCII UTF-8, i prawdopodobnie nawet uszkodzi znaki, ponieważ wycina wielobajtowe znaki w połowie sekwencji.

Oto wersja obsługująca 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])
}

1
To wymaga o wiele więcej głosów pozytywnych - właśnie zostałem mocno ugryziony, nie używając dzielenia świadomego utf-8.
kolaente


2

8 lat później natknąłem się na ten klejnot, a mimo to nie wierzę, że na pierwotne pytanie OP rzeczywiście została udzielona odpowiedź:

więc wymyśliłem następujący kod, aby przyciąć znak nowego wiersza

Chociaż bufio.Readertyp obsługuje ReadLine() metodę, która zarówno usuwa, jak \r\ni \njest rozumiana jako funkcja niskiego poziomu, która jest niewygodna w użyciu, ponieważ konieczne są wielokrotne sprawdzenia.

IMO idiomatycznym sposobem na usunięcie białych znaków jest użycie biblioteki ciągów znaków Golanga :

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)

Zobacz ten przykład w akcji na placu zabaw Golang: https://play.golang.org/p/HrOWH0kl3Ww

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.