How to match by regexp 3 and 4 bytes UTF-8

Viewed 561

I just want to find 3-byte character in Go using regexp. But it panic with

regexp: Compile(\x{E29AA4}): error parsing regexp: invalid escape sequence: \x{E29AA4

func get_words_from(text string) []string {
   words := regexp.MustCompile(`\x{E29AA4}`)
    return words.FindAllString(text, -1)
}

func main() {
    text := "One,ВАПОЛтлдо⚤two ыаплд⚤ы ыапю.ы./\tавthree!"
    fmt.Println(get_words_from(text))
}

You can try on playground

2 Answers

Decode the UTF-8 byte sequence E2 9A A4 with e.g. utf8.DecodeRune() and use the resulting rune in the regexp:

func get_words_from(text string) []string {
    r, _ := utf8.DecodeRune([]byte{0xE2, 0x9A, 0xA4})
    words := regexp.MustCompile(string(r))
    return words.FindAllString(text, -1)
}

You may also simply convert the byte slice to string (which interprets it as UTF-8 encoded bytes):

func get_words_from2(text string) []string {
    s := string([]byte{0xE2, 0x9A, 0xA4})
    words := regexp.MustCompile(s)
    return words.FindAllString(text, -1)
}

Or use the equivalent unicode code point (which is 0x26a4) in the regexp string:

func get_words_from3(text string) []string {
    words := regexp.MustCompile("\u26a4")
    return words.FindAllString(text, -1)
}

Note that "\u26a4" is an interpreted string literal and will be unescaped by the Go compiler (not the regexp package).

All examples return (try the examples on the Go Playground):

[⚤ ⚤]

To filter out all runes that have 3 or more bytes in UTF-8, you may use a for range and utf8.RuneLen():

text := "One,ВАПОЛтлдо⚤two ыаплд⚤ы ыапю.ы./\tавthree!"
fmt.Println(text)

var out []rune
for _, r := range text {
    if utf8.RuneLen(r) < 3 {
        out = append(out, r)
    }
}
fmt.Println(string(out))

This outputs (try it on the Go Playground):

One,ВАПОЛтлдо⚤two ыаплд⚤ы ыапю.ы./  авthree!
One,ВАПОЛтлдоtwo ыаплды ыапю.ы./    авthree!

Or use strings.Map(), where you return -1 for such runes, which then will be left out in the result:

out := strings.Map(func(r rune) rune {
    if utf8.RuneLen(r) < 3 {
        return r
    }
    return -1
}, text)
fmt.Println(string(out))

This outputs the same. Try this one on the Go Playground.

Also I found that character ⚤ in regex can match by \xE2\x9A\xA4 instead of wrong: \x{E29AA4}

Related