1

Given such a code:

str := "hi hey hello"
regexpr := `(?i)hello|hey|hi`
fmt.Println(regexp.MustCompile(regexpr).FindStringSubmatch(str))

it gives such result:

[hi]

But I want to get a [hello] as a result. Because in my case 'hello' is first priority, second priority is 'hey', and then 'hi'. How can I achieve it ?

I only know the solution to put keywords in slice and loop it. But it would not with single regexp operation.

Is it possible to do with single regexp operation ?

Mikael
  • 1,209
  • 1
  • 16
  • 47
  • 1
    Regex engine searches from left to right, and the first match is `hi` in the string. You probably can use `(?i).*(hello)|.*(hey)|.*(hi)` and get the captured word out of the match. See [this Go playground](https://play.golang.org/p/hSK2aqfPQ7l) and [regex demo](https://regex101.com/r/GkP4f0/2). – Wiktor Stribiżew May 16 '20 at 12:53
  • @WiktorStribiżew hm, I need to get only one match. 'hello' is most important here. Seems I have to use loop.. – Mikael May 16 '20 at 12:59
  • 1
    `|` is the so-called "alternation" in a regular expressions, and I know of no RE engine which would support any sorts of assigning "preference" to the alternation elements (well, the RE engine prefers the matches of the elements from left to right, but it's for the case several of them could math at once). Hence I'd use `(?i)\b(hello|hi|hey)\b` with `regexp.FindAllSubmatches*` to get the ordered list of matched words and then process them with your "preference" criteria. – kostix May 16 '20 at 13:30
  • My regex shows exactly how you can get that match. What do you need to get in the end? Substring? Indices of positions? – Wiktor Stribiżew May 16 '20 at 13:56
  • @WiktorStribiżew, yes I want to get substring matched to first most important keywoed (hello), or if 'hello' doesn't exists then 'hey' and so on – Mikael May 16 '20 at 14:02
  • 4
    Then ``regexpr := `(?i).*?(hello)|.*?(hey)|.*?(hi)` `` with `regexp.MustCompile(regexpr).FindStringSubmatch(str)[1]` is what you need – Wiktor Stribiżew May 16 '20 at 14:04
  • @WiktorStribiżew, yes it does, thank you! – Mikael May 17 '20 at 17:16

1 Answers1

1

You should bear in mind that regex engine searches for matches from left to right. Thus, to "set prioroty to an alternative" means "let each aternative match at any position to the right of the current location".

You should use

regexpr := `(?i).*?(hello)|.*?(hey)|.*?(hi)`

Here, .*? will match any 0 or more chars other than line break chars, as few as possible. In the code, use

regexp.MustCompile(regexpr).FindStringSubmatch(str)[1]

See Go playground demo:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    str := "hi hey hello"
    regexpr := `(?i).*?(hello)|.*?(hey)|.*?(hi)`
    fmt.Println(regexp.MustCompile(regexpr).FindStringSubmatch(str)[1])
}
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563