Go言語(プログラミング)入門メモ㉖

## 便利な標準パッケージを使用する
時間に関するパッケージであるtimeと正規表現について扱うregexpを使用する。

## 時間に関するコードを書く
時間を表す形式は様々あり、日本では「2006年1月2日」のような順序で表現するが、アメリカでは月日のあとに都市という順番で表現することもある。
よく使われるフォーマットとしてRFC3339がある。PostgreSQLで時間のデータをtimeという型に代入する場合はRFC3339の形式にして代入する。
timeを使用してコードを改訂見る。time.Nowで現在時刻を表示できる。
~~~
import (
	"fmt"
	"time"
)

func main() {
	t := time.Now()
	fmt.Println(t)
}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/a594140a-ca20-91a7-411c-525f7b664cc9.png)
これをRFC3339の形式にする場合、以下のようにFormatメソッドで「time.RFC3339」を指定する
~~~
func main() {
	t := time.Now()
	fmt.Println(t)
    fmt.Println(t.Format(time.RFC3339))
}
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/7e1825e8-ce26-9c66-288d-b730af022302.png)

## 年月日や時刻を単独で表示する
t.Year(),t.Month(),t.Day(),t.Hour(),t.Minute(),t.Second()でそれぞれ年、月、日付、時、分、秒を表示できる。
~~~
func main() {
	t := time.Now()
	fmt.Println(t)
	fmt.Println(t.Format(time.RFC3339))
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
}
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/be2bd9db-66b0-e58d-685f-d33ad4bf5ebf.png)

## 正規表現のコードを書く
regexp(レジェックスと読む。pは発音しないのか)は正規表現を扱うパッケージ。正規表現とは、条件に当てはまる文字列を検索するときに使われる表現。
例としては以下のようなものがある
[a-z]:aからzまでの任意の一文字
a+:aという文字が一文字以上連続する部分
a|b|c:a,b,cのいずれかの文字
^a:先頭がaから始まる文字列
a$:末尾がaで終わる文字列
まず、matchという変数を初期化する。エラーは_で無視するようにする。MatchString関数を使い、引数に「a([a-z]+)e」という正規表現とappleという文字列を書く。MatchString関数は、正規表現が文字列に一致していればtrue、そうでなければfalseを返す。
「a([a-z]+)e」という正規表現は、「aとeの間に、aからzまでの任意の文字が一文字以上入る」という文字列、という意味になる。この結果をfmt.Prinltnで表示すると、trueになる。
~~~
import (
	"fmt"
	"regexp"
)

func main(){
    match, _ := regexp.MatchString("a([a-z]+)e", "apple")
	fmt.Println(match)
}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/c0d4c327-c260-83a5-d04e-8cd629e7535f.png)
ここで、比較する文字列を「appl0e」と数字の0を入れて実行すると結果はfalseになる。
~~~
import (
	"fmt"
	"regexp"
)

func main(){
    match, _ := regexp.MatchString("a([a-z]+)e", "appl0e")
	fmt.Println(match)
}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/ef1ed5c7-5740-0959-4f9d-ae34e211b74b.png)

さらに、この「appl0e」でも正規表現に当てはまらせるようにするには、「a([a-z0-9]+)e」と書く。この正規表現は、「aとeの間にaからzまでの任意の文字か0から9までの任意の文字が1つ以上入る」という意味。
~~~
import (
	"fmt"
	"regexp"
)

func main(){
    match, _ := regexp.MatchString("a([a-z0-9]+)e", "apple")
	fmt.Println(match)
}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/93a01441-0c05-d695-7e4a-82dd63d48e9d.png)

## MustCompile関数
MustCompile関数は正規表現に使用するregexpオブジェクトを返す。同じ正規表現を繰り返し使用する場合は、MatchString関数よりもMustCompile関数のほうが高速な処理となる。
MustCompile関数の引数に正規表現を書き、regexpオブジェクトのメソッドであるMatchStringメソッドを使って、文字列が正規表現に一致しているかを確認できる。
~~~
import (
	"fmt"
	"regexp"
)

func main() {
	r := regexp.MustCompile("a([a-z]+)e")
	ms := r.MatchString("apple")
	fmt.Println(ms)
}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/c2804963-d111-ee19-d000-9aed7f209f97.png)

## FindStringメソッド
FindStringメソッドは、正規表現に一致するもっとも左側の文字列を返す。
まずMustCompile関数で正規表現のオブジェクトを作成する。正規表現は、「^/(edit|save|view)/([a-z0-9]+)$」とする。この正規表現は、「先頭に/、その次にedit,save,viewのどれか、次に/が入って、さらにその次にaからzの任意の文字または0から9の任意の数字が入って文字列の最後となる」という意味。
FindStringメソッドを用いて「/view/test」と正規表現を満たす形を引数とし実行する。
~~~
package main

import (
	"fmt"
	"regexp"
)

func main() {
	r2 := regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
	fs := r2.FindString("/view/test")
	fmt.Println(fs)

}
~~~
以下のように、指定した正規表現を満たす場合は、引数が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/d89704c3-7b70-4522-08c8-f7e5239e806a.png)
正規表現に一致しない場合は、何も表示されない
~~~
package main

import (
	"fmt"
	"regexp"
)

func main() {
	r2 := regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
	fs := r2.FindString("e/view/test")
	fmt.Println(fs)

}
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/200be4a1-c81f-0267-d517-73fbef77d5db.png)

## FindStringSubmatchメソッド
FindStringSubmatchメソッドは、正規表現に一致する文字列とともに、正規表現の()で囲まれた部分に一致する部分も併せてスライスで返す。
コードを実行すると、「[/view/test view test]」というスライスが表示される。スライスの0番目には正規表現に一致する文字列「/view/test」が、1番目と2番目には()で囲まれた「(edit|save|view)」と「([a-zA-Z0-9]+)」にそれぞれ一致する、「view」と「test」が格納される。
~~~
package main

import (
	"fmt"
	"regexp"
)

func main() {
	r2 := regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
	fss := r2.FindStringSubmatch("/view/test")
	fmt.Println(fss, fss[0], fss[1], fss[2])

}
~~~
実行結果は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/63f7bda9-c089-5db7-8061-2653d6e19ff2.png)
viewをeditやsaveに変更して実行しても同様に出力される。
~~~
package main

import (
	"fmt"
	"regexp"
)

func main() {
	r2 := regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
	fss := r2.FindStringSubmatch("/edit/test")
	fmt.Println(fss, fss[0], fss[1], fss[2])
	fss = r2.FindStringSubmatch("/save/test")
	fmt.Println(fss, fss[0], fss[1], fss[2])

}
~~~
実行結果は以下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/1734c1d1-96e3-8ce4-31dc-23a5d54d5568.png)

このようなパッケージは、たとえば、Webサーバのバックエンドにて、URLによって処理を変えたいときにregexpを使って判定しプログラムを書いていくといったユースケースがある。
## 学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP

・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897