2 回答

TA貢獻(xiàn)1777條經(jīng)驗(yàn) 獲得超10個贊
因?yàn)榇婊畹姆纳儆趗tf8.RuneSelf,這個問題可以通過對字節(jié)進(jìn)行操作來解決。如果任何字節(jié)不在 中[^a-zA-Z0-9 ]
,則該字節(jié)是要刪除的符文的一部分。
func strip(s string) string {
? ? var result strings.Builder
? ? for i := 0; i < len(s); i++ {
? ? ? ? b := s[i]
? ? ? ? if ('a' <= b && b <= 'z') ||
? ? ? ? ? ? ('A' <= b && b <= 'Z') ||
? ? ? ? ? ? ('0' <= b && b <= '9') ||
? ? ? ? ? ? b == ' ' {
? ? ? ? ? ? result.WriteByte(b)
? ? ? ? }
? ? }
? ? return result.String()
}
此函數(shù)的一個變體是通過調(diào)用 result.Grow 來預(yù)分配結(jié)果:
func strip(s string) string {
? ? var result strings.Builder
? ? result.Grow(len(s))
? ? ...
這確保函數(shù)進(jìn)行一次內(nèi)存分配,但如果幸存符文與源符文的比率較低,則內(nèi)存分配可能會大大超過所需。
此答案中的函數(shù)strip被編寫為與參數(shù)和結(jié)果類型一起使用,string因?yàn)檫@些是問題中使用的類型。
如果應(yīng)用程序正在處理源文本并且可以修改該源文本,那么就地[]byte更新會更有效。[]byte為此,將幸存的字節(jié)復(fù)制到切片的開頭并在完成后重新切片。這避免了 strings.Builder 中的內(nèi)存分配和開銷。這種變化類似于 peterSO 對這個問題的回答。
func strip(s []byte) []byte {
? ? n := 0
? ? for _, b := range s {
? ? ? ? if ('a' <= b && b <= 'z') ||
? ? ? ? ? ? ('A' <= b && b <= 'Z') ||
? ? ? ? ? ? ('0' <= b && b <= '9') ||
? ? ? ? ? ? b == ' ' {
? ? ? ? ? ? s[n] = b
? ? ? ? ? ? n++
? ? ? ? }
? ? }
? ? return s[:n]
}
根據(jù)使用的實(shí)際數(shù)據(jù),此答案中的一種方法可能比問題中的方法更快。

TA貢獻(xiàn)1853條經(jīng)驗(yàn) 獲得超6個贊
從大文本中刪除所有非字母數(shù)字字符的有效方法。
在 Go 中,“高效方式”意味著我們運(yùn)行 Gotesting
包基準(zhǔn)測試。
您對大文本的描述含糊不清。讓我們假設(shè)它以來自文件或其他byte
切片的文本開始。
string([]byte)
您可能有、幾個make([]byte)
和 的開銷string([]byte)
。
您可以使用strings.Builder
將開銷減少到string([]byte)
和 幾個make([]byte)
。
string([]byte)
您可以通過從函數(shù)開始進(jìn)一步減少它clean([]byte) string
。
例如,
func clean(s []byte) string {
j := 0
for _, b := range s {
if ('a' <= b && b <= 'z') ||
('A' <= b && b <= 'Z') ||
('0' <= b && b <= '9') ||
b == ' ' {
s[j] = b
j++
}
}
return string(s[:j])
}
對于大文,莎士比亞全集作為一部[]byte,
$ go fmt && go test strip_test.go -bench=. -benchmem
BenchmarkSendeckyMap-8 20 65988121 ns/op 11730958 B/op 2 allocs/op
BenchmarkSendeckyRegex-8 5 242834302 ns/op 40013144 B/op 130 allocs/op
BenchmarkThunder-8 100 21791532 ns/op 34682926 B/op 43 allocs/op
BenchmarkPeterSO-8 100 16172591 ns/op 5283840 B/op 1 allocs/op
$
strip_test.go:
package main
import (
"io/ioutil"
"regexp"
"strings"
"testing"
)
func stripMap(str, chr string) string {
return strings.Map(func(r rune) rune {
if strings.IndexRune(chr, r) >= 0 {
return r
}
return -1
}, str)
}
var alphanum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
func BenchmarkSendeckyMap(b *testing.B) {
for N := 0; N < b.N; N++ {
b.StopTimer()
bytShakespeare := []byte(strShakespeare)
b.StartTimer()
strShakespeare = string(bytShakespeare)
stripMap(strShakespeare, alphanum)
}
}
func stripRegex(in string) string {
reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+")
return reg.ReplaceAllString(in, "")
}
func BenchmarkSendeckyRegex(b *testing.B) {
for N := 0; N < b.N; N++ {
b.StopTimer()
bytShakespeare := []byte(strShakespeare)
b.StartTimer()
strShakespeare = string(bytShakespeare)
stripRegex(strShakespeare)
}
}
func strip(s string) string {
var result strings.Builder
for i := 0; i < len(s); i++ {
b := s[i]
if ('a' <= b && b <= 'z') ||
('A' <= b && b <= 'Z') ||
('0' <= b && b <= '9') ||
b == ' ' {
result.WriteByte(b)
}
}
return result.String()
}
func BenchmarkThunder(b *testing.B) {
for N := 0; N < b.N; N++ {
b.StopTimer()
bytShakespeare := []byte(strShakespeare)
b.StartTimer()
strShakespeare = string(bytShakespeare)
strip(strShakespeare)
}
}
func clean(s []byte) string {
j := 0
for _, b := range s {
if ('a' <= b && b <= 'z') ||
('A' <= b && b <= 'Z') ||
('0' <= b && b <= '9') ||
b == ' ' {
s[j] = b
j++
}
}
return string(s[:j])
}
func BenchmarkPeterSO(b *testing.B) {
for N := 0; N < b.N; N++ {
b.StopTimer()
bytShakespeare := []byte(strShakespeare)
b.StartTimer()
clean(bytShakespeare)
}
}
var strShakespeare = func() string {
// The Complete Works of William Shakespeare by William Shakespeare
// http://www.gutenberg.org/files/100/100-0.txt
data, err := ioutil.ReadFile(`/home/peter/shakespeare.100-0.txt`)
if err != nil {
panic(err)
}
return string(data)
}()
- 2 回答
- 0 關(guān)注
- 183 瀏覽
添加回答
舉報(bào)