goで簡単なコマンドラインツールを書くためのメモ (コマンド引数パース,外部コマンド実行,正規表現,APIリクエスト,jsonパース,xmlパース)

go初心者なので、こうした方がいいなどガンガンフィードバックいただきたいです。

# コマンドの引数を取得する

固定の引数は`flag.Arg(0)`で取得、オプションのコマンドは`flag.Int()`などから取得
引数が必須なときは`len(flag.Args()) `でチェック

```
go run command_argument.go --count=3 hello 
```

```
hello
hello
hello
```


```go
package main

import (
	"flag"
	"fmt"
)

func main() {
	count := flag.Int("count", 1, "count is int")
	flag.Parse()
	if len(flag.Args()) < 1 {
		fmt.Println("need argument")
		return
	}

	for i := 0; i < *count; i++ {
		fmt.Println(flag.Arg(0))
	}
}

```


# コマンドの実行

ls -lの実行して表示

```go
package main

import (
	"os/exec"
	"fmt"
	"os"
)

func main() {
	output, err := exec.Command("ls", "-la").Output()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	println(string(output))
}
```

http://qiita.com/tanksuzuki/items/9205ff70c57c4c03b5e5 より

# 正規表現

公式に素晴らしい例があったので、、それを持ってきました
https://gobyexample.com/regular-expressions

```go
package main

import (
	"regexp"
	"fmt"
	"bytes"
)

// https://gobyexample.com/regular-expressions
func main() {

	// 簡単に含まれるか確認
	match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
	fmt.Println(match) // true

	// パターン作成
	r, _ := regexp.Compile("p([a-z]+)ch")

	// パターンが含まれるか
	fmt.Println(r.MatchString("peach")) // true

	// パターンを検索
	fmt.Println(r.FindString("peach punch")) // peach

	// パターンを検索して、その文字のインデックスを取得
	fmt.Println(r.FindStringIndex("peach punch")) // [0 5]

	// 最初にヒットしたものと、中のグループを取り出す
	fmt.Println(r.FindStringSubmatch("peach punch")) // [peach ea]

	// Similarly this will return information about the
	// indexes of matches and submatches.
	fmt.Println(r.FindStringSubmatchIndex("peach punch")) // [0 5 1 3]

	// The `All` variants of these functions apply to all
	// matches in the input, not just the first. For
	// example to find all matches for a regexp.
	fmt.Println(r.FindAllString("peach punch pinch", -1)) // [peach punch pinch]

	// These `All` variants are available for the other
	// functions we saw above as well.
	fmt.Println(r.FindAllStringSubmatchIndex( // [[0 5 1 3] [6 11 7 9] [12 17 13 15]]
		"peach punch pinch", -1))

	// Providing a non-negative integer as the second
	// argument to these functions will limit the number
	// of matches.
	fmt.Println(r.FindAllString("peach punch pinch", 2)) // [peach punch]

	// Our examples above had string arguments and used
	// names like `MatchString`. We can also provide
	// `[]byte` arguments and drop `String` from the
	// function name.
	fmt.Println(r.Match([]byte("peach"))) // true

	// When creating constants with regular expressions
	// you can use the `MustCompile` variation of
	// `Compile`. A plain `Compile` won't work for
	// constants because it has 2 return values.
	r = regexp.MustCompile("p([a-z]+)ch")
	fmt.Println(r) // p([a-z]+)ch

	// The `regexp` package can also be used to replace
	// subsets of strings with other values.
	fmt.Println(r.ReplaceAllString("a peach", "<fruit>")) // a <fruit>

	// The `Func` variant allows you to transform matched
	// text with a given function.
	in := []byte("a peach")
	out := r.ReplaceAllFunc(in, bytes.ToUpper)
	fmt.Println(string(out)) // a PEACH
}

```


# API アクセスして、JSONの要素にアクセスする

リクエストに`net/http`を使い、レスポンスの取得に`ioutil.ReadAll()`を使い、レスポンスをオブジェクトに変換を`json.Unmarshal()`でする感じです。

```go
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

type Route struct {
	Summary string `json:"summary"`
}
type Response struct {
	Routes []Route `json:"routes"`
}

func main() {
	body := request()
	fmt.Println(string(body))

	response := new(Response)
	if err := json.Unmarshal(body, &response); err != nil {
		log.Println("JSON Unmarshal error:", err)
		return
	}
	fmt.Println(string(response.Routes[0].Summary))
}
func request() []byte {
	client := &http.Client{}
        // クエリを加工しない場合はhttp.Getで十分っぽい
	req, err := http.NewRequest("GET", "http://maps.googleapis.com/maps/api/directions/json",
		nil)
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}
	q := req.URL.Query()
	q.Add("origin", "tokyo")
	q.Add("destination", "osaka")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Print("Request error:", err)
		os.Exit(1)
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	return body
}
```

これで こういう感じで表示されます

```json
{
...
   "routes" : [
      {
...
         "summary" : "新東名高速道路",
 }
   ],
   "status" : "OK"
}
```

```
新東名高速道路
```

# API アクセスして、XMLの要素にアクセスする

ほぼ同じ、jsonがxmlになって`encoding/xml`を使うようになったのみです

```go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"encoding/xml"
)

type Route struct {
	Summary string `xml:"summary"`
}
type Response struct {
	Routes Route `xml:"route"`
}

func main() {
	body := request()
	fmt.Println(string(body))

	response := new(Response)
	if err := xml.Unmarshal(body, &response); err != nil {
		log.Println("JSON Unmarshal error:", err)
		return
	}
	fmt.Println(string(response.Routes.Summary))
}
func request() []byte {
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://maps.googleapis.com/maps/api/directions/xml",
		nil)
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}
	q := req.URL.Query()
	q.Add("origin", "tokyo")
	q.Add("destination", "osaka")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Print("Request error:", err)
		os.Exit(1)
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	return body
}
```