snippetgoMinor
Parse Numerals from a String in Golang
Viewed 0 times
fromparsenumeralsgolangstring
Problem
I recently tried my hand at writing Go code for a project I'm working on. In order to help myself get a better grasp I decided to write a simple yet somewhat practical program for parsing numeral characters from strings based on the ascii values of the runes within, and appending them to a slice.
My primary concerns with this code are:
Note: The code below contains the documentation comments. Since this is my first time using Stack Exchange, I'm not entirely certain whether or not this is reasonable and it makes the read a little long.
```
/*
parseNum package
This is a package which contains a function for converting characters
(charToInt), in the form of runes, into numerals. It also contains a
function for parsing numerals from strings (parseNum).
*/
package main
import (
"errors"
"fmt"
)
/*
CharToNum function
This is a function which recieves a rune and converts it to a numeral
based on its ascii code by matching it against the numeral ascii codes
in a for loop. It subtracts 48 from the code to get the actual numeral,
as the ascii codes for numerals are 48-57 and simple subtraction gives
you the actual numeral.
*/
func CharToNum(r rune) (int, error) {
for i := 48; i <= 57; i++ {
if int(r) == i {
return (int(r) - 48), nil
}
}
return -1, errors.New("type: rune was not int")
}
/*
ParseNum function
This is a function which serves the purpose of identifying numerals inside
strings and returning them in a slice. It loops over the string, passing each
character to the charToNum function and identifying whether it should append the
output to the array by testing whether or not the error evaluates to nil.
*/
func ParseNum(str string) []int {
var nums []int
for _, val := range str {
num, err := CharToNum(val)
if err
My primary concerns with this code are:
- It may not be a good solution.
- It may not be very performant.
- It may not be very idiomatic or reflective of best practices.
- It may not be very concise, clean, or readable.
Note: The code below contains the documentation comments. Since this is my first time using Stack Exchange, I'm not entirely certain whether or not this is reasonable and it makes the read a little long.
```
/*
parseNum package
This is a package which contains a function for converting characters
(charToInt), in the form of runes, into numerals. It also contains a
function for parsing numerals from strings (parseNum).
*/
package main
import (
"errors"
"fmt"
)
/*
CharToNum function
This is a function which recieves a rune and converts it to a numeral
based on its ascii code by matching it against the numeral ascii codes
in a for loop. It subtracts 48 from the code to get the actual numeral,
as the ascii codes for numerals are 48-57 and simple subtraction gives
you the actual numeral.
*/
func CharToNum(r rune) (int, error) {
for i := 48; i <= 57; i++ {
if int(r) == i {
return (int(r) - 48), nil
}
}
return -1, errors.New("type: rune was not int")
}
/*
ParseNum function
This is a function which serves the purpose of identifying numerals inside
strings and returning them in a slice. It loops over the string, passing each
character to the charToNum function and identifying whether it should append the
output to the array by testing whether or not the error evaluates to nil.
*/
func ParseNum(str string) []int {
var nums []int
for _, val := range str {
num, err := CharToNum(val)
if err
Solution
In your question, you wrote:
In his answer, Janos wrote:
Using idiomatic Go, I wrote,
It's simple and direct and it's fast. Benchmarking the numbers zero through nine:
Benchmarking the invalid numeric character space (
The error variable
In your question, you wrote:
Using idiomatic Go, I wrote,
It minimizes both CPU time and memory allocations; it's fast. Benchmarking the string
Unicode and UTF-8 characters corresponding to the ASCII set have the same byte values as ASCII.
See Benchmarks, Package testing.
func CharToNum(r rune) (int, error) {
for i := 48; i <= 57; i++ {
if int(r) == i {
return (int(r) - 48), nil
}
}
return -1, errors.New("type: rune was not int")
}In his answer, Janos wrote:
func CharToNum(r rune) (int, error) {
intval := int(r) - '0'
if 0 <= intval && intval <= 9 {
return intval, nil
}
return -1, errors.New("type: rune was not int")
}Using idiomatic Go, I wrote,
var ErrRuneNotInt = errors.New("type: rune was not int")
func CharToNum(r rune) (int, error) {
if '0' <= r && r <= '9' {
return int(r) - '0', nil
}
return 0, ErrRuneNotInt
}It's simple and direct and it's fast. Benchmarking the numbers zero through nine:
BenchmarkCharToNumTschfld 5000000 323 ns/op
BenchmarkCharToNumPeter 50000000 37.7 ns/opBenchmarking the invalid numeric character space (
' '):BenchmarkCharToNumErrTschfld 10000000 242 ns/op 16 B/op 1 allocs/op
BenchmarkCharToNumErrPeter 2000000000 1.26 ns/op 0 B/op 0 allocs/opThe error variable
ErrRuneNotInt can be used to check for a specific error, for example, if err == ErrRuneNotInt {}.In your question, you wrote:
func ParseNum(str string) []int {
var nums []int
for _, val := range str {
num, err := CharToNum(val)
if err != nil {
continue
}
nums = append(nums, num)
}
return nums
}Using idiomatic Go, I wrote,
func ParseNum(s string) []int {
nLen := 0
for i := 0; i < len(s); i++ {
if b := s[i]; '0' <= b && b <= '9' {
nLen++
}
}
var n = make([]int, 0, nLen)
for i := 0; i < len(s); i++ {
if b := s[i]; '0' <= b && b <= '9' {
n = append(n, int(b)-'0')
}
}
return n
}It minimizes both CPU time and memory allocations; it's fast. Benchmarking the string
"000123456789000":BenchmarkParseNumTschfld 1000000 2475 ns/op 248 B/op 5 allocs/op
BenchmarkParseNumPeter 2000000 610 ns/op 128 B/op 1 allocs/opUnicode and UTF-8 characters corresponding to the ASCII set have the same byte values as ASCII.
See Benchmarks, Package testing.
Code Snippets
func CharToNum(r rune) (int, error) {
for i := 48; i <= 57; i++ {
if int(r) == i {
return (int(r) - 48), nil
}
}
return -1, errors.New("type: rune was not int")
}func CharToNum(r rune) (int, error) {
intval := int(r) - '0'
if 0 <= intval && intval <= 9 {
return intval, nil
}
return -1, errors.New("type: rune was not int")
}var ErrRuneNotInt = errors.New("type: rune was not int")
func CharToNum(r rune) (int, error) {
if '0' <= r && r <= '9' {
return int(r) - '0', nil
}
return 0, ErrRuneNotInt
}BenchmarkCharToNumTschfld 5000000 323 ns/op
BenchmarkCharToNumPeter 50000000 37.7 ns/opBenchmarkCharToNumErrTschfld 10000000 242 ns/op 16 B/op 1 allocs/op
BenchmarkCharToNumErrPeter 2000000000 1.26 ns/op 0 B/op 0 allocs/opContext
StackExchange Code Review Q#122831, answer score: 4
Revisions (0)
No revisions yet.