удалить нулевой символ из строки - PullRequest
0 голосов
/ 21 января 2019

Я хочу проверить, пуста ли строка, и проанализировать строку во времени.

Пожалуйста, найдите следующий код

valueStr = strings.Replace(string(valueStr), " ", "", -1)
valueStr = strings.Replace(string(valueStr), "\t", "", -1)
valueStr = strings.Replace(string(valueStr), "\n", "", -1)
valueStr = strings.Replace(string(valueStr), "\r", "", -1)
var re = regexp.MustCompile(`\s`)
valueStr = re.ReplaceAllString(valueStr, "")

if valueStr != "" {
    fmt.Printf("-------- valueStr %c: \n", valueStr)         // o/p =>  -------- valueStr %!c(string= ):
    fmt.Printf("-------- valueStr %#v: \n", valueStr)        // o/p => -------- valueStr "\x00":
    fmt.Printf("-------- valueStr %x: \n", valueStr)         // o/p =>  -------- valueStr 00:
    fmt.Println("-------- valueStr length: ", len(valueStr)) // o/p => -------- valueStr length:  1

    // considering valueStr is not empty, parse string to time

    time, err := time.Parse(TIME_FORMAT, strings.TrimSpace(valueStr))
    if err != nil {
        fmt.Println("-------- Error converting time: ", err) // o/p => -------- Error converting time:  parsing time " " as "15:04:05": cannot parse " " as "15"
        return
    }
} else {
    // another code
}

Как удалить этот пустой символ из строки?Или проверить, содержит ли строка этот пустой символ?

1 Ответ

0 голосов
/ 21 января 2019

Вы можете удалить \x00 рун из строки так же, как вы можете удалить любые другие руны:

valueStr = strings.Replace(valueStr, "\x00", "", -1)

Пример:

s := "a\x00b"
fmt.Printf("%q\n", s)
s = strings.Replace(s, "\x00", "", -1)
fmt.Printf("%q\n", s)

Вывод (попробуйте на Go Playground ):

"a\x00b"
"ab"

Использование strings.Replacer

Также обратите внимание, что вы можете заменить несколько замен одной операцией, используя strings.Replacer, и он также будет более эффективным, поскольку он будет повторять только один раз вход (и для результата будет выделен только один string независимо от того, сколько подстрок вы хотите заменить).

Например:

s := " \t\n\rabc\x00"
fmt.Printf("%q\n", s)

r := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\x00", "")
s = r.Replace(s)
fmt.Printf("%q\n", s)

Вывод (попробуйте на Go Playground ):

" \t\n\rabc\x00"
"abc"

Также обратите внимание, что достаточно создать string.Replacer один раз,и вы можете сохранить его в (глобальной) переменной и использовать повторно, даже безопасно использовать его одновременно с несколькими программами.

Использование strings.Map()

Также обратите внимание, что если вы хотите толькочтобы заменить (удалить) одиночные rune s, а не многорядные (или многобайтовые) подстроки, вы также можете использовать strings.Map(), который может быть даже более эффективным, чем strings.Replacer.

Сначала определите функцию, которая сообщает, какие rune s заменить (или удалить, если вы возвращаете отрицательное значение):

func remove(r rune) rune {
    switch r {
    case ' ', '\t', '\n', '\r', 0:
        return -1
    }
    return r
}

И затем с его помощью:

s := " \t\n\rabc\x00"
fmt.Printf("%q\n", s)

s = strings.Map(remove, s)
fmt.Printf("%q\n", s)

Вывод (попробуйте на Go Playground ):

" \t\n\rabc\x00"
"abc"

Тесты

Мы могли быдумаю, что strings.Map() будет лучше, поскольку он должен иметь дело только с rune s, которые являются просто int32 числами, в то время как strings.Replacer должен иметь дело с string значениями, которые являются заголовками (длина + указатель данных) плюс рядбайтов.

Но мы должны знать, что значения string хранятся в памяти как байтовые последовательности UTF-8, что означает, что strings.Map() необходимо декодировать rune из байтовой последовательности UTF-8 (и закодировать руны обратно в UTF-8 в конце), в то время как strings.Replacer этого не делает: он может просто искать совпадения последовательности байтов без декодирования rune s.И strings.Replacer высоко оптимизирован, чтобы использовать в своих интересах такие «уловки».

Итак, давайте создадим тест для сравнения:

Мы будем использовать их для тестов:

var r = strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\x00", "")

func remove(r rune) rune {
    switch r {
    case ' ', '\t', '\n', '\r', 0:
        return -1
    }
    return r
}

И мы запускаем тесты для разных строк ввода:

func BenchmarkReplaces(b *testing.B) {
    cases := []struct {
        title string
        input string
    }{
        {
            title: "None",
            input: "abc",
        },
        {
            title: "Normal",
            input: " \t\n\rabc\x00",
        },
        {
            title: "Long",
            input: "adsfWR \t\rab\nc\x00 \t\n\rabc\x00asdfWER\n\r",
        },
    }

    for _, c := range cases {
        b.Run("Replacer-"+c.title, func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                r.Replace(c.input)
            }
        })
        b.Run("Map-"+c.title, func(b *testing.B) {
            for i := 0; i < b.N; i++ {
                strings.Map(remove, c.input)
            }
        })
    }

}

А теперь давайте посмотрим результаты теста:

BenchmarkReplaces/Replacer-None-4    100000000   12.3 ns/op    0 B/op  0 allocs/op
BenchmarkReplaces/Map-None-4         100000000   16.1 ns/op    0 B/op  0 allocs/op
BenchmarkReplaces/Replacer-Normal-4  20000000    92.7 ns/op    6 B/op  2 allocs/op
BenchmarkReplaces/Map-Normal-4       20000000    92.4 ns/op   16 B/op  2 allocs/op
BenchmarkReplaces/Replacer-Long-4     5000000   234 ns/op     64 B/op  2 allocs/op
BenchmarkReplaces/Map-Long-4          5000000   235 ns/op     80 B/op  2 allocs/op

Несмотря на ожидания, string.Replacer работает довольно хорошо,так же хорошо, как strings.Map(), потому что нет необходимости декодировать и кодировать руны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...