Простая версия, в которой пропущены недопустимые руны, может выглядеть следующим образом:
func forceASCII(s string) string {
rs := make([]rune, 0, len(s))
for _, r := range s {
if r <= 127 {
rs = append(rs, r)
}
}
return string(rs)
}
// forceASCII("Hello, World!") // => "Hello, World!"
// forceASCII("Hello, 世界!") // => "Hello, !"
// forceASCII("Привет") // => ""
Но что, если вам нужно особое поведение, если целевая строка UTF-8 содержит символы вне диапазона символов ASCII [0,127]
?
Вы можете написать функцию, которая обрабатывает различные случаи, извлекая аргумент функции, который принимает руну invalid-ASCII и возвращает замену строки или ошибку.
Например ( Go Playground ):
func forceASCII(s string, replacer func(rune) (string, error)) (string, error) {
rs := make([]rune, 0, len(s))
for _, r := range s {
if r <= 127 {
rs = append(rs, r)
} else {
replacement, err := replacer(r)
if err != nil {
return "", err
}
rs = append(rs, []rune(replacement)...)
}
}
return string(rs), nil
}
func main() {
replacers := []func(r rune) (string, error){
// omit invalid runes
func(_ rune) (string, error) { return "", nil },
// replace with question marks
func(_ rune) (string, error) { return "?", nil },
// abort with error */
func(r rune) (string, error) { return "", fmt.Errorf("invalid rune 0x%x", r) },
}
ss := []string{"Hello, World!", "Hello, 世界!"}
for _, s := range ss {
for _, r := range replacers {
ascii, err := forceASCII(s, r)
fmt.Printf("OK: %q → %q, err=%v\n", s, ascii, err)
}
}
// OK: "Hello, World!" → "Hello, World!", err=<nil>
// OK: "Hello, World!" → "Hello, World!", err=<nil>
// OK: "Hello, World!" → "Hello, World!", err=<nil>
// OK: "Hello, 世界!" → "Hello, !", err=<nil>
// OK: "Hello, 世界!" → "Hello, ??!", err=<nil>
// OK: "Hello, 世界!" → "", err=invalid rune 0x4e16
}