Извлечение подстрок в Go

114

Я пытаюсь прочитать с консоли всю строку (включая пробелы), а затем обработать ее. Используя bufio.ReadString, символ новой строки читается вместе с вводом, поэтому я придумал следующий код для обрезки символа новой строки:

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

Есть ли более идиоматический способ сделать это? То есть существует ли уже библиотека, которая заботится о конечном нулевом байте при извлечении подстрок за вас?

(Да, я знаю, что уже есть способ прочитать строку без символа новой строки в go readline -> string, но я ищу больше элегантных манипуляций со строкой.)

mark2222
источник

Ответы:

146

Похоже, вас смущает работа срезов и формат хранения строк, который отличается от того, что у вас есть в C.

  • любой фрагмент в Go хранит длину (в байтах), поэтому вам не нужно заботиться о стоимости lenоперации: нет необходимости считать
  • Строки Go не заканчиваются нулем, поэтому вам не нужно удалять нулевой байт, и вам не нужно добавлять 1после нарезки, добавляя пустую строку.

Чтобы удалить последний символ (если это однобайтовый символ), просто выполните

inputFmt:=input[:len(input)-1]
Дени Сегюре
источник
11
Вам даже не нужен 0 (или :), s = s[:len(s)-1]подойдет.
uriel 07
8
Обратите внимание, что этот метод не будет работать со строками Unicode! groups.google.com/forum/#!msg/golang-nuts/ZeYei0IWrLg/…
Melllvar
@Melllvar Вот почему я уточнил, «если это однобайтовый символ» . Если вы хотите удалить символ, занимающий более одного байта (это не случай OP), вам нужно адаптироваться.
Denys Séguret
25

Строки Go не заканчиваются нулем, и чтобы удалить последний символ строки, вы можете просто сделать:

s = s[:len(s)-1]
Уриэль
источник
10
Это неверно и вызовет ошибки. Это удаляет последний байт из строки, что может сделать ее недействительной UTF-8 (или другой многобайтовой кодировкой).
доктор Sybren
3
См. Play.golang.org/p/K3HBBtj4Oi, чтобы увидеть, как это ломается.
доктор Sybren
10

Чтобы избежать паники при вводе нулевой длины, оберните операцию усечения в if

input, _ := src.ReadString('\n')
var inputFmt string
if len(input) > 0 {
    inputFmt = input[:len(input)-1]
}
// Do something with inputFmt
Рохантевиз
источник
9

Это самый простой способ выполнить подстроку в 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

ПРЕДУПРЕЖДЕНИЕ: работа только со строками будет работать только с ASCII и будет считаться неверным, если ввод является символом в кодировке, отличном от ASCII UTF-8, и, вероятно, даже приведет к повреждению символов, поскольку он вырезает многобайтовые символы в середине последовательности.

Вот версия с поддержкой 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
источник
1
Для этого нужно гораздо больше голосов - меня просто сильно укусило, что я не использовал разделение с учетом utf-8.
kolaente
2

8 лет спустя я наткнулся на этот драгоценный камень, и все же я не верю, что на исходный вопрос OP действительно был дан ответ:

поэтому я придумал следующий код, чтобы обрезать символ новой строки

Хотя этот bufio.Readerтип поддерживает ReadLine() метод, который одновременно удаляет, \r\nи \nон предназначен как функция низкого уровня, которую неудобно использовать, потому что необходимы повторные проверки.

IMO идиоматический способ удалить пробелы - использовать библиотеку строк 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)

Посмотрите этот пример в действии на игровой площадке Голанга: https://play.golang.org/p/HrOWH0kl3Ww

Филипп Пиксель
источник