How do I include operators in my output when I split a string?

I asked this question yesterday about splitting a string in python. Since then, I have decided to do this project in Go instead. I have the following:

input := "house-width + 3 - y ^ (5 * house length)"
s := regexp.MustCompile(" ([+-/*^]) ").Split(input, -1)
log.Println(s)  //  [house-width 3 y (5 house length)]

      

How do I include operators in this output? e.g. I need the following output:

['house-width', '+', '3', '-', 'y', '^', '(5', '*', 'house length)']

      

EDIT: To clarify, I am breaking down on space-separated operators, not just the operator. The operator must have a space at both ends to distinguish it from a dash / hyphen. Please refer to my original python question I linked to for clarification if needed.

+3


source to share


3 answers


You can get the operands of your expression using regexp.Split()

(as you do) and you can get operators (delimiters) using regexp.FindAllString()

.

With this you will have 2 separate []string

slices, you can combine these 2 slices if you want to get the result in one slice []string

.

input := "house-width + 3 - y ^ (5 * house length)"

r := regexp.MustCompile(`\s([+\-/*^])\s`)

s1 := r.Split(input, -1)
s2 := r.FindAllString(input, -1)

fmt.Printf("%q\n", s1)
fmt.Printf("%q\n", s2)

all := make([]string, len(s1)+len(s2))
for i := range s1 {
    all[i*2] = s1[i]
    if i < len(s2) {
        all[i*2+1] = s2[i]
    }
}
fmt.Printf("%q\n", all)

      

Conclusion (try it on the Go Playground ):

["house-width" "3" "y" "(5" "house length)"]
[" + " " - " " ^ " " * "]
["house-width" " + " "3" " - " "y" " ^ " "(5" " * " "house length)"]

      



Note:

If you want to trim whitespace from operators, you can use the function strings.TrimSpace()

:

for i, v := range s2 {
    all[i*2+1] = strings.TrimSpace(v)
}
fmt.Printf("%q\n", all)

      

Output:

["house-width" "+" "3" "-" "y" "^" "(5" "*" "house length)"]

      

+1


source


If you plan to parse the expression after this, you need to make some changes:

  • Include parentheses as tokens
  • You cannot make both spaces and dashes be valid identification characters, for example, for example. - y

    inbetween 3

    and ^

    will be a valid ID.

After that, you can use a simple linear iteration to lex your string:



package main

import (
    "bytes"
    "fmt"
)

func main() {

    input := `house width + 3 - y ^ (5 * house length)`
    buffr := bytes.NewBuffer(nil)
    outpt := make([]string, 0)

    for _, r := range input {
        if r == '+' || r == '-' || r == '*' || r == '/' || r == '^' || r == '(' || r == ')' || (r >= '0' && r <= '9') {
            bs := bytes.TrimSpace(buffr.Bytes())
            if len(bs) > 0 {
                outpt = append(outpt, (string)(bs))
            }
            outpt = append(outpt, (string)(r))
            buffr.Reset()
        } else {
            buffr.WriteRune(r)
        }
    }

    fmt.Printf("%#v\n", outpt)

}

      

After lexed, use the Dijkstra maneuvering algorithm to build an AST or evaluate an expression directly.

+1


source


I think FindAll () might be the way to go.

Extended regex:

 \s*                           # Trim preceding whitespace
 (                             # (1 start), Operator/Non-Operator chars
      (?:                           # Cluster group
           \w -                          # word dash
        |  - \w                          # or, dash word
        |  [^+\-/*^]                     # or, a non-operator char
      )+                            # End cluster, do 1 to many times
   |                              # or,
      [+\-/*^]                      # A single simple math operator
 )                             # (1 end)
 \s*                           # Trim trailing whitespace

      

Snippet code:

http://play.golang.org/p/bHZ21B6Tzi

package main

import (
"log"
"regexp"
)
func main() {
    in := []byte("house-width + 3 - y ^ (5 * house length)")
    rr := regexp.MustCompile("\\s*((?:\\w-|-\\w|[^+\\-/*^])+|[+\\-/*^])\\s*")
    s := r.FindAll( in, -1 )
    for _, ss:=range s{
      log.Println(string(ss))
    }
}

      

Output:

 house-width 
 + 
 3 
 - 
 y 
 ^ 
 (5 
 * 
 house length)

      

0


source







All Articles