"BOKU"のITな日常

興味のむくまま気の向くままに調べたり・まとめたりしてます。

GO言語(golang)/文字列の分割・結合・文字列出現位置検査・比較などの基本操作

f:id:arakan_no_boku:20210412005751p:plain

目次

今回確認すること

日本語文字列に対し頻繁に使う「文字列」操作ができるか?を確認します。

正規表現は使いません。

確かめるのに使う文字列です。

var s = " 漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在 "

半角全角の英数字かなカナ漢字混在で、前に半角空白、後ろに全角空白があります。

確かめは、こんな感じでソースコードを書いてやってます。

package main

import (
	"fmt"
	"strings"
)

func main() {
	var s string = " 漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在 "
	ps := strings.TrimSpace(s)
	fmt.Print(ps)
}

さて、やってみます。

トリム(前後の空白を削除)

 "strings"をimportして、以下のようにします。

ps := strings.TrimSpace(s)

結果は こう。

漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在

両端の半角も全角も空白が削除されてます。

大文字変換

 "strings"をimportして、以下のようにします。

ps := strings.ToUpper(s)

半角も全角も大文字変換されます。

 漢字123456ABCDEFGHIJKLひらがなカタカナハンカナ混在  

小文字変換

 "strings"をimportして、以下のようにします。

ps := strings.ToLower(s)

半角も全角も小文字変換されます。

漢字123456abcdefghijklひらがなカタカナハンカナ混在 

全角変換・半角変換

golang.org/x/text/widthをimportします。

importエラーになるときは、「go get」でローカルにインストールします。

(たぶん、VSCodeが候補を表示してくれますけど)

全角変換は以下のようなソースになります。

package main

import (
	"fmt"

	"golang.org/x/text/width"
)

func main() {
	var s string = " 漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在 "
	ps := width.Widen.String(s)
	fmt.Print(ps)
}

結果は半角カナも含めて、全角になってます。

漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在

半角変換は、WidenをNarrowに変えます。

ps := width.Narrow.String(s)

漢字とひらがな以外は半角になります。

カナが半角カナになっているのがすごいです。

  漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在 

全角・半角変換のひとつの目的として、文字列比較の前処理があります。

それに便利そうな、 Foldというのも使えます。

ps := width.Fold.String(s)

漢字・ひらがな・カタカナを全角に、英数字を半角に統一してくれます。

ちょうど「いい塩梅の変換」だと自分は思います。 

結果はこうです。

漢字123456abcdefGHIJKLひらがなカタカナハンカナ混在

数字から文字列へ返還

"strconv"をimportします。

整数を文字列にするのは「Itoa」

i := 12345
ps := strconv.Itoa(i)

浮動小数点数を文字列には「FormatFloat」。3つ目の引数で小数点以下の桁数です。

j := 1234.567
ps = strconv.FormatFloat(j, 'f', 6, 64)

それぞれの結果が

12345
1234.567000

strconvはほかにもいろいろあります。

文字列からboolやfloatなどにパースするパターン、

b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.1415", 64)
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)

逆に文字列にフォーマットするパターン。

s := strconv.FormatBool(true)
s := strconv.FormatFloat(3.1415, 'E', -1, 64)
s := strconv.FormatInt(-42, 16)
s := strconv.FormatUint(42, 16)

などなど。

文字列の分割

 "strings"をimportして、以下のようにします。

「c」で文字列を2つに分割して、[]をつけて表示してみます。

ps := strings.Split(s, "c")
for _, str := range ps {
	fmt.Printf("[%s]", str)
}

「c」がセパレータになって2分割されてます。 

[ 漢字123456ab][defGHIJKLひらがなカタカナハンカナ混在 ]

文字列の切り出し(スライス)

 文字列をスライスで切り出すことができます。

ps := s[4:10]
ps = s[:4]
ps = s[16:]

[開始:終了]で指定しますが、開始は0から始まり、開始から終了の前のバイトまで取得しますが、ちょっと癖があります。

  • 半角文字:1文字1バイト
  • 全角文字:1文字3バイト

で計算して位置を決めないといけません。

開始を未指定は先頭から、終了未指定は最後まで・・になります。

なので、上記の結果は以下のようになります。

字123

6abcdefGHIJKLひらがなカタカナハンカナ混在

文字列の連結

 文字列を「+」でぺたぺた連結できます。

i := 12345
j := 4567.34
ps := "整数を文字列に「" + strconv.Itoa(i) + "」+浮動小数点を文字列に「" + strconv.FormatFloat(j, 'f', 6, 64) + "」"

 結果はこう。

整数を文字列に「12345」+浮動小数点を文字列に「4567.340000」

文字列中に指定文字列が含まれるか検査

strings.containsを使います。

b := strings.Contains(s, "がな")

結果はtrue、falseで戻されます。

文字列中の指定文字列の出現位置

 stringsのIndex(最初の位置)、LastIndex(最後の位置)を使います。

var s string = "僕の「かばん」と君の「かばん」は同じ「かばん」なのか?"
idx := strings.Index(s, "「かばん」")
lidx := strings.LastIndex(s, "「かばん」")

これで結果が最初の位置が「6」、最後の位置が「54」とかえってきます。 

文字数ではなく、全部全角文字なので、1文字=3バイト計算です。

文字列の長さ

len()を使います。

l := len("「かばん」")

これで結果は「15」と返ります。

これも「全角文字=3バイト」として計算しているからです。

全角文字5文字 = 3 × 5 = 15・・ということです。

文字列のスライスに使うなら、まあ、こうなってないとな・・という感じです。

これはいやだな・・文字数を数えたい・・場合は、こんなやり方になります。

l := len([]rune("「かばん」"))

こうすると文字数の「5」がかえります。

runeの概念は今回ははしょります。)

文字列の比較

単純に文字列を比較するだけなら「==」でいけます。

	var sa1 = "123漢字かなカナ"
	var sa2 = "123漢字かなカナ"
	var sb = "123漢字かなカナ"
	if sa1 == sa2 {
		fmt.Println("OK")
	} else {
		fmt.Println("NG")
	}

	if sa1 == sb {
		fmt.Println("OK")
	} else {
		fmt.Println("NG")
	}

全角と半角を区別して比較してます。

まあ、当たり前。

これを全角・半角を無視して比較したいときは、前に書いた「Fold」で変換してフォーマットをあわせてやればよさげです。

	var sa1 = "123漢字かなカナ"
	var sb = "123漢字かなカナ"

	psa1 := width.Fold.String(sa1)
	psb := width.Fold.String(sb)

	if psa1 == psb {
		fmt.Println("OK2")
	} else {
		fmt.Println("NG2")
	}

こうすれば、結果は「OK2」になります。

stringsパッケージに「strings.EqualFold」というのがあって、なんとなくそれを使えば同じように比較できそうに思えますが、全角・半角まで考慮はしてくれません。

以下のように、半角の大文字・小文字の違いだけなら無視できます。

	var a = "abcですよ"
	var b = "ABCですよ"

	if strings.EqualFold(a, b) {
		fmt.Println("OK3")
	} else {
		fmt.Println("NG3")
	}

とりあえず、今回はこのくらいですかね。

ではでは。