Skip to content

Instantly share code, notes, and snippets.

@ifukazoo
Created March 28, 2017 00:15
Show Gist options
  • Save ifukazoo/e207c684d72f163c6ad8c965df545b6d to your computer and use it in GitHub Desktop.
Save ifukazoo/e207c684d72f163c6ad8c965df545b6d to your computer and use it in GitHub Desktop.
crontab形式のパース
package main
import (
"bufio"
"errors"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
var (
scanner *bufio.Scanner
)
func init() {
scanner = bufio.NewScanner(os.Stdin)
}
func eSplitLine() ([]string /*eof*/, bool) {
if !scanner.Scan() {
if err := scanner.Err(); err != nil {
os.Exit(1)
}
return []string{}, true
}
return strings.Split(scanner.Text(), " "), false
}
// CronTabFmt crontab フォーマット
type CronTabFmt interface {
GetValues() []int
}
// ScalFmt スカラーフォーマット
type ScalFmt int
// GetValues 単一の値を返す
func (i ScalFmt) GetValues() []int {
return []int{int(i)}
}
// RangeFmt 範囲を持つフォーマット
type RangeFmt struct {
begin int
end int
}
// GetValues 範囲内の値を返す
func (r RangeFmt) GetValues() []int {
var hours []int
for i := r.begin; i <= r.end; i++ {
hours = append(hours, i)
}
return hours
}
// IntervalFmt 範囲と間隔を持つフォーマット
type IntervalFmt struct {
begin int
end int
interval int
}
// GetValues 範囲内の有効な値を返す
func (interval IntervalFmt) GetValues() []int {
var hours []int
for i := interval.begin; i <= interval.end; i += interval.interval {
hours = append(hours, i)
}
return hours
}
func parseScal(input string) (int, error) {
var (
i int
err error
)
if i, err = strconv.Atoi(input); err != nil {
return 0, errors.New("parseScal error:" + input)
}
return i, nil
}
func parseRange(input string) ([]int, error) {
if input == "*" {
return []int{0, 23}, nil
}
beginAndEnd := strings.Split(input, "-")
if len(beginAndEnd) != 2 {
return []int{}, errors.New("parseRange error:" + input)
}
var (
begin, end int
err error
)
if begin, err = parseScal(beginAndEnd[0]); err != nil {
return []int{}, err
}
if end, err = parseScal(beginAndEnd[1]); err != nil {
return []int{}, err
}
return []int{begin, end}, nil
}
func parseInterval(input string) ([]int, error) {
numerAndDenom := strings.Split(input, "/")
if len(numerAndDenom) != 2 {
return []int{}, errors.New("parseInterval error:" + input)
}
var (
beginAndEnd []int
interval int
err error
)
if beginAndEnd, err = parseRange(numerAndDenom[0]); err != nil {
return []int{}, err
}
if interval, err = strconv.Atoi(numerAndDenom[1]); err != nil {
return []int{}, err
}
return []int{beginAndEnd[0], beginAndEnd[1], interval}, nil
}
func parseScalFmt(input string) (ScalFmt, error) {
val, err := parseScal(input)
return ScalFmt(val), err
}
func parseRangeFmt(input string) (RangeFmt, error) {
var (
val []int
err error
)
if val, err = parseRange(input); err != nil {
return RangeFmt{}, err
}
return RangeFmt{val[0], val[1]}, nil
}
func parseIntervalFmt(input string) (IntervalFmt, error) {
var (
val []int
err error
)
if val, err = parseInterval(input); err != nil {
return IntervalFmt{}, err
}
return IntervalFmt{val[0], val[1], val[2]}, nil
}
func parseField(field string) ([]CronTabFmt, error) {
var (
fmts []CronTabFmt
s ScalFmt
r RangeFmt
i IntervalFmt
err error
)
strs := strings.Split(field, ",")
for _, v := range strs {
// try IntervalFmt
if i, err = parseIntervalFmt(v); err == nil {
fmts = append(fmts, i)
continue
}
// try RangeFmt
if r, err = parseRangeFmt(v); err == nil {
fmts = append(fmts, r)
continue
}
// try ScalFmt
if s, err = parseScalFmt(v); err == nil {
fmts = append(fmts, s)
continue
}
// error!
return []CronTabFmt{}, err
}
return fmts, nil
}
func getHourValues(field string) ([]int, error) {
var (
crontabFmt []CronTabFmt
err error
)
if crontabFmt, err = parseField(field); err != nil {
return []int{}, err
}
// map を setとして利用する
hourSet := make(map[int]int)
for _, fmt := range crontabFmt {
nums := fmt.GetValues()
for _, n := range nums {
if 0 <= n && n < 24 { // 0〜23の値にフィルター
hourSet[n] = 0 // 0は使用しない値
}
}
}
// set から値を取り出してソートして返す
var values []int
for h := range hourSet {
values = append(values, h)
}
sort.Ints(values)
return values, nil
}
func main() {
for {
var (
fields []string
eof bool
)
if fields, eof = eSplitLine(); eof {
break
}
var (
err error
hours []int
)
if hours, err = getHourValues(fields[1]); err != nil {
os.Exit(1)
}
sep := ""
for _, h := range hours {
fmt.Printf("%v%v", sep, h)
sep = " "
}
fmt.Println("")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment