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.
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)"]
source to share
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
inbetween3
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.
source to share
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)
source to share