1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Golang】文字間の複数ホワイトスペースを削除して1つのスペースに置き換える関数(全角スペース含む)

Last updated at Posted at 2022-10-06

Go 言語(以下 Golang)で、文字列内の文字間にある複数スペースやタブを 1 つに変換したい。ついでに、全角スペースも。

つまり、単語間の空白を詰めたいのです。

こういうことがしたい(before-->after)
" Hello,    World  ! "			--> "Hello, World !"
"Hello,\tWorld ! "				--> "Hello, World !"
" \t\n\t Hello,\tWorld\n!\n\t"	--> "Hello, World !"
# 以下は全角スペース
"     Hello,  World!  "				--> "Hello, World!"

「golang 文字間の複数スペースを削除する」でググっても、正規表現や strings.ReplaseAll を使った方法だったり、文字列の前後のトリムばかりだったので、自分のググラビリティとして。

TL; DR (今北産業)

  1. strings.Fields 関数を使う
  2. strings.Fields()strings.Split 関数の親戚で、連続するホワイト・スペース(空白、タブや改行)は 1 つとして扱う
  3. strings.Fields() で分解し、strings.Join() で再度組み合わせると単語間の空白を詰められる
単語間を詰める関数
// TrimWordGaps は、文字列内の連続した空白文字を 1 文字のスペースに変換します。
// 具体的な使い方・サンプルは TS; DR 参照
func TrimWordGaps(s string) string {
	return strings.Join(strings.Fields(s), " ")
}

TS; DR

strings.Fields とは

func Fields
func Fields(s string) []string

Fields splits the string s around each instance of one or more consecutive white space characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an empty slice if s contains only white space.
Fields | strings @ pkg.go.dev より)

【筆者訳】
Fields は、1 つ以上の連続したホワイト・スペースで囲まれている文字の周りで文字列 s を分割し、その部分文字列のスライスを返します。また、s が空白のみを含む場合は空のスライスを返します。なお、ホワイト・スペースは unicode.IsSpaceで定義されている空白文字です。

つまり、strings.Fields()strings.Slice() の変形バージョンです。

例えば strings.Slice(s, " ") は、s 内でヒットした " " ごとに分割するのに対し、strings.Fields(s) は連続している空白文字(ホワイトスペース)を 1 文字として扱い s を分割します。

動作サンプル

サンプル(全角スペース含む)
package main

import (
	"fmt"
	"strings"
	"testing"
)

func TrimWordGaps(s string) string {
	return strings.Join(strings.Fields(s), " ")
}

func ExampleTrimWordGaps() {
	result := TrimWordGaps("    Hello,       World     !    ")

	fmt.Println(result)

	// Output: Hello, World !
}

func TestTrimWordGaps(t *testing.T) {
	for i, test := range []struct {
		input  string
		expect string
	}{
		{
			input:  " Hello,   World  ! ",
			expect: "Hello, World !",
		},
		{
			input:  "Hello,\tWorld ! ",
			expect: "Hello, World !",
		},
		{
			input:  " \t\n\t Hello,\tWorld\n!\n\t",
			expect: "Hello, World !",
		},
		{
			// 全角スペース入り
			input:  "     Hello,  World!  ",
			expect: "Hello, World!",
		},
	} {
		nameTest := fmt.Sprintf("test #%d (Input:%#v)", i, test.input)

		t.Run(nameTest, func(t *testing.T) {
			actual := TrimWordGaps(test.input)
			if test.expect != actual {
				t.Fail()
			}
		})
	}
}
// Output:
// === RUN   TestTrimWordGaps
// === RUN   TestTrimWordGaps/test_#0_(Input:"_Hello,___World__!_")
// === RUN   TestTrimWordGaps/test_#1_(Input:"Hello,\tWorld_!_")
// === RUN   TestTrimWordGaps/test_#2_(Input:"_\t\n\t_Hello,\tWorld\n!\n\t")
// === RUN   TestTrimWordGaps/test_#3_(Input:"\u3000\u3000\u3000\u3000\u3000Hello,\u3000\u3000World!\u3000\u3000")
// --- PASS: TestTrimWordGaps (0.00s)
//     --- PASS: TestTrimWordGaps/test_#0_(Input:"_Hello,___World__!_") (0.00s)
//     --- PASS: TestTrimWordGaps/test_#1_(Input:"Hello,\tWorld_!_") (0.00s)
//     --- PASS: TestTrimWordGaps/test_#2_(Input:"_\t\n\t_Hello,\tWorld\n!\n\t") (0.00s)
//     --- PASS: TestTrimWordGaps/test_#3_(Input:"\u3000\u3000\u3000\u3000\u3000Hello,\u3000\u3000World!\u3000\u3000") (0.00s)
// === RUN   ExampleTrimWordGaps
// --- PASS: ExampleTrimWordGaps (0.00s)
// PASS

参考文献

1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?