カテゴリー: go

  • Go言語での正規表現

    Go言語での正規表現

    はじめに

    Go言語内の文字列の判定で正規表現を使う際の“regexp”ライブラリについてまとめる

    使い方

    MatchString

    正規表現のフォーマットに沿った文字列か確認し、True/Falseを返す

    	match, _ := regexp.MatchString("b([a-z]+)a", "banana")
    	fmt.Println(match)

    結果

    true

    しかし、この書き方では複数の文字に対してチェックしたい場合、都度正規表現を書かなくてはならない。

    MustCompile

    以下の書き方をすることで正規表現の定義は一度のみでよくなる

    	r := regexp.MustCompile("b([a-z]+)a")
    	ms1 := r.MatchString("banana")
    	fmt.Println(ms1)
    	ms2 := r.MatchString("apple")
    	fmt.Println(ms2)
    	ms3 := r.MatchString("orange")
    	fmt.Println(ms3)

    結果

    true
    false
    false

    FindString

    MustCompileの中でURIを正規表現で定義し、
    FindStringで、そのルールに収まっているか確認をするという使い方もできる。
    	r2 := regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
    	fs := r2.FindString("/view/test")
    	fmt.Println(fs)

    結果

    /view/test

    もしヒットしない場合は、結果を返さない。

    FindStringSubmatch

    格納されるデータはスライスで入っているので、一つ一つ取り出すことも可能。

    	fss := r2.FindStringSubmatch("/view/test")
    	fmt.Println(fss[0])
    	fmt.Println(fss[1])
    	fmt.Println(fss[2])

    結果は以下の通り

    /view/test
    view
    test

     

  • go言語で時間を制御する

    go言語で時間を制御する

    はじめに

    どの言語でも時間を表示したり、プログラムに利用したいことが多々ある。

    go言語でよくつかうライブラリ time について整理する。

    公式ドキュメントはこちら

    https://godoc.org/time

    時間のフォーマットは世界中にいろいろある。

    const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
        RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
        RFC822      = "02 Jan 06 15:04 MST"
        RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
        RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
        RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
        RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
        RFC3339     = "2006-01-02T15:04:05Z07:00"
        RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
        Kitchen     = "3:04PM"
        // Handy time stamps.
        Stamp      = "Jan _2 15:04:05"
        StampMilli = "Jan _2 15:04:05.000"
        StampMicro = "Jan _2 15:04:05.000000"
        StampNano  = "Jan _2 15:04:05.000000000"
    )

    今回は我々日本人に馴染みのあるRCF3339を利用することとする

    サンプルプログラム

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	//現在時間を取得する
    	t := time.Now()
    	fmt.Println(t)
    
    	// RCF3339 formatに変換する
    	fmt.Println(t.Format(time.RFC3339))
    
    	// 年月日を取得する
    	fmt.Println(t.Year(), t.Month(), t.Day())
    
    	// 月を数字(April -> 4 に変換する)
    	fmt.Println(t.Year(), int(t.Month()), t.Day())
    
    	// 時分秒を表示
    	fmt.Println(t.Hour(), t.Minute(), t.Second())
    }

    出力結果

    2019-04-06 11:13:36.125176 +0900 JST m=+0.000473714
    2019-04-06T11:13:36+09:00
    2019 April 6
    2019 4 6
    11 13 36
    

    “` int(t.Month()) “` とすることで数字(4月など)に変換できるのは面白い。

     

     

  •  go言語で株価を取得する

     go言語で株価を取得する

    はじめに

    株価情報を取得したいことがある。

    go言語ではパッケージを利用することにより株価の取得が非常に簡単にできている。

    利用するライブラリ

    https://github.com/markcheno/go-talib

    サンプルコードや導入手順もこちらに記載されてある。

    go get github.com/markcheno/go-talib
    go get github.com/markcheno/go-quote

    実施するコマンド

    Googleの株価を取得する。

    オリジナルはこちら

    https://finance.yahoo.com/quote/GOOG?p=GOOG&.tsrc=fin-srch

    package main
    
    import (
    	"fmt"
    
    	"github.com/markcheno/go-quote"
    	"github.com/markcheno/go-talib"
    )
    
    func main() {
    	spy, _ := quote.NewQuoteFromYahoo("GOOG", "2019-04-01", "2019-04-04", quote.Daily, true)
    	fmt.Print(spy.CSV())
    	rsi2 := talib.Rsi(spy.Close, 2)
    	fmt.Println(rsi2)
    }

    実行結果

    $ go run main.go
    datetime,open,high,low,close,volume
    2019-04-01 00:00,1184.10,1196.66,1182.00,1194.43,1252500.00
    2019-04-02 00:00,1195.32,1201.35,1185.71,1200.49,827900.00
    2019-04-03 00:00,1207.48,1216.30,1200.50,1205.92,1017800.00
    [0 0 100]

     

     

     

  • go言語でtestingを使ったunittestの方法

    go言語でtestingを使ったunittestの方法

    はじめに

    あらゆるプログラミング言語でunitテストという作業は必要だが、今回はそのgo言語版について説明する。

    今回はgoのデフォルトの “` testing “` を使い、ライブラリのテストを行うものとする。

    ディレクトリ構成

    $ tree
    .
    ├── library
    │   ├── Ave.go # ライブラリ
    │   └── Ave_test.go # ライブラリのテストプログラム
    └── main.go # 呼び出し元

    テスト対象

    library/Ave.go は以下の通り

    package library
    
    func Average(s []int) int {
    	total := 0
    	for _, i := range s {
    		total += i
    	}
    	return int(total / len(s))
    }

    受け取ったスライスを元に、平均を計算し、

    平均値を返す

    テストプログラム

    テストプログラムは

    “` import “testing” “`

    を行い、functionは 

    “` func TestAverage(t *testing.T) “`

    という名前で作成する必要がある。

    package library
    
    import "testing"
    
    func TestAverage(t *testing.T) {
    	v := Average([]int{1, 2, 3, 4, 5})
    	if v != 3 {
    		t.Error("Expected 3, got", v)
    	}
    }

    テストプログラムを実施する

    テスト実施コマンドはこちら

    “` go test ./… “`

    現在のディレクトリで全てのテストプログラムを実施するという意味。

     

    テスト結果(成功時のパターン)

    $ go test ./...
    ?       github.com/GitSumito/go-sample  [no test files] # testがありません
    ok      github.com/GitSumito/go-sample/library  0.009s

    libraryのテストが完了した

    詳細を確認する際は “` -v “` オプションを実施する

    $ go test ./... -v
    ?       github.com/GitSumito/go-sample  [no test files]
    === RUN   TestAverage
    --- PASS: TestAverage (0.00s)
    PASS
    ok      github.com/GitSumito/go-sample/library  0.008s

     

    テスト結果(失敗時のパターン)

    テストコードをあえて失敗するよう修正する

    package library
    
    import "testing"
    
    func TestAverage(t *testing.T) {
    	v := Average([]int{1, 2, 3, 4, 5, 6, 7, 8, 9})
    	if v != 3 {
    		t.Error("Expected 3, got", v)
    	}
    }

    再度テストを実行

    $ go test ./... -v
    ?       github.com/GitSumito/go-sample  [no test files]
    === RUN   TestAverage
    --- FAIL: TestAverage (0.00s)
            Ave_test.go:8: Expected 3, got 5
    FAIL
    FAIL    github.com/GitSumito/go-sample/library  0.008s

    テストをskipさせる

    Skipを使うことによりスキップさせることが可能

    package library
    
    import "testing"
    
    var Debug bool = true
    
    func TestAverage(t *testing.T) {
    
    	if Debug {
    		t.Skip("Skip Reason")
    	}
    
    	v := Average([]int{1, 2, 3, 4, 5, 6, 7, 8, 9})
    	if v != 3 {
    		t.Error("Expected 3, got", v)
    	}
    }

    結果

    $ go test ./... -v
    ?       github.com/GitSumito/go-sample  [no test files]
    === RUN   TestAverage
    --- SKIP: TestAverage (0.00s)
            Ave_test.go:10: Skip Reason
    PASS
    ok      github.com/GitSumito/go-sample/library  0.009s

     参考情報

    本記事は、udemyの講座で得た情報をメモとしてまとめました。非常に濃厚な講義ですので、以下の講座を強くお勧めします。

    https://www.udemy.com/go-fintech/

     

     

  • go routine/channelを整理する

    go routine/channelを整理する

    go routineのchannelについて勉強したので整理する

    package main
    
    import (
    	"fmt"
    )
    
    // sliceとchannelを受け付ける
    func goroutine(s []int, c chan int) {
    	sum := 0
    	for _, v := range s {
    		sum += v
    	}
    	// channelに送信
    	c <- sum
    }
    
    // channel
    
    func main() {
    	// スライスのinteger
    	s := []int{1, 2, 3, 4, 5}
    	// channel (makeで書く)
    	// makeはキューの働きをする
    	c := make(chan int)
    	go goroutine(s, c)
    
    	// チャネルを受信。ブロッキングの役割があるので、入ってくるまでずっと待っている状態
    	x := <-c
    	fmt.Println(x)
    }

    結果 “` 15 “`

  • Go言語のアドレスとポインタを整理する

    Go言語のアドレスとポインタを整理する

    はじめに

    goを弄る際、必ずと言っていいほど毎回調べている気がするので整理する。

    サンプルプログラム

    package main
    
    import "fmt"
    
    func one(x *int) {
    	*x = 1
    }
    
    func main() {
    
    	var n int = 100
    	one(&n)
    	fmt.Println(n)
    	fmt.Println(&n)
    }
    

    サンプルプログラムの出力結果

    1
    0xc420084008

     

    解説

    function oneはintのアドレスを引数に受け付ける

    “` * “` はポインタ型の箱として理解する

    fmt.Println(*n) とした場合、箱の中身。

    上記例でいうと100が表示される。

     

    “` & “` はアドレスとして理解する。上記例でいうと0xc420084008とかになる。