QiitaのtagフィードをCLIで見るためのCLIツールをGo言語で書いた

[Zennのこちらの記事(フィードを取得する Go 言語パッケージ)](https://zenn.dev/spiegel/articles/20201003-feed-with-golang) を読んで、[gofeed](https://github.com/mmcdole/gofeed)という便利なツールがあることを知り、触ってみたくなったので、QiitaのtagフィードをCLI上で表示するだけの、シンプルなツールを作ってみました。

[qiita-tag-feed-reader-cli - CLI reader of Qiita tag feed.](https://github.com/shinshin86/qiita-tag-feed-reader-cli)

## qiita-tag-feed-reader-cliの使い方
上のリンク先にある[README](https://github.com/shinshin86/qiita-tag-feed-reader-cli/blob/main/README.md)のままの説明になりますが、下記のとおりです。

```bash
# install
go get github.com/shinshin86/qiita-tag-feed-reader-cli

# ランダムにタグを指定してフィードを表示する
qiita-tag-feed-reader-cli

# 指定したタグのフィードを表示する(この場合は"Go"でも"go"でもOK)
qiita-tag-feed-reader-cli Go

# 勿論、日本語も使えます
qiita-tag-feed-reader-cli セキュリティ
```

完全にgofeed触りたかったのと、Go自体の勉強目的のために作ったようなツールですが、意外とビルド中などのちょっとした空き時間に使えるようなツールになったので、一応こちらでもご報告させていただいた次第です。
(なにより `Qiita` に関連したもののため)

ソース自体は、非常に小規模なため、どういうことをやっているかは直接ソースコードを読んで頂くのが一番良いかと思います。
が、一応、Qiitaに書いているわけだし、技術ポイント(と言えるほどじゃないですが)を書き残しておきます。

## gofeedについては解説しません

なお、ここまで話しておいてちゃぶ台をひっくり返すようですが、`gofeed`自体の使い方は[gofeedのREADME](https://github.com/mmcdole/gofeed/blob/master/README.md)と、上に貼ったZennのポストを見れば分かるレベルなので、割愛します。

以前自分でもGoで、取得したfeedをパースするコードを書いたことがありましたが、gofeedがあれば、そこらへんの処理を一気にすっ飛ばせるので、便利だなと思いました。使いやすいツールです。


## CLIならではの表示順序
実際にコマンドを叩いていただくと分かると思いますが、情報は下記のような並びで表示しています。
これは、CLI上で使う故、下から上へと目線が動いていくことを考慮したものとなっています。

```bash
・
・
・
----------------------------------------------------
<feed items>
-----------------------
<feed items>
-----------------------
<feed items>
-----------------------
<feed title>
<feed type> <feed version>
======================
```

## フィードに関する情報
gofeedを使いたかったということもあり、tagのフィードを取得しています。
このフィードURLについては下記のQiitaポストを参考にさせていただきました。

[Qiita 記事／ユーザ／Organization／タグ のフィード URL（フォローしたいユーザーやタグの XML/ATOM の URL） - タグ・フィードの URL](https://qiita.com/KEINOS/items/f0a5bce2fa9cfec85f8b#%E3%82%BF%E3%82%B0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89%E3%81%AE-url)

## 取得したHTMLのHTMLタグを除去する処理

HTMLタグを除去する処理は下記のコードを参考に実装させていただいています。
(というか、HTMLコメントを対応した以外はほとんど同じだ...)
https://gist.github.com/g10guang/04f11221dadf1ed019e0d3cf3e82caf3

実際に `qiita-tag-feed-reader-cli` 内で書いてあるHTMLタグ除去のソースコードを下記に載せます。

```go
func removeHTMLTag(html string) string {
	const pattern = `(<\/?[a-zA-A!-]+?[^>]*\/?>)*`
	r := regexp.MustCompile(pattern)
	groups := r.FindAllString(html, -1)

	// Replace the long string first
	sort.Slice(groups, func(i, j int) bool {
		return len(groups[i]) > len(groups[j])
	})

	for _, group := range groups {
		if strings.TrimSpace(group) != "" {
			html = strings.ReplaceAll(html, group, "")
		}
	}
	return html
}
```

参照元のコードを見ながら実装していたときに、なるほどなーと思ったのは、上のコードのコメントにもあるように、文字列を長い順から置換していっているところです。

というのも、こちらの正規表現でタグを抜き出した場合、取得したタグのパターンとしては、例えば下記のような２パターンのタグが取得できます。

```html
</span></div>
```

```html
</span>
```

`strings.ReplaceAll`でHTMLを置換していく際、`</span>`から先に置換された場合、 `</span></div>`は取り残されてしまうため、長い文字列から置換を行うようにしています。
これですべてのHTMLタグの除去に成功します。

本当はこの挙動をちゃんと証明するためのテストコードも必要ですが、早く形にしたかったので横着しました。
せっかくなので、後日テストコードも追加しようと思います。
→追記: テストを追加しました。

## Qiitaのtagをランダムに取得する部分について
これは技術ポイントではないのですが、このツールを引数無しで実行した場合、Qiitaのtagをランダムに選択してfeedを表示しようとします。
このQiitaのtagについては下記のコードを参照して、人気順にtagを取得しています。

[(Qiita API v2 活用) Qiita のタグ情報を API 経由で取得する方法 - タグを指定しないで取得するサンプルコード](https://qiita.com/kojiro-s/items/3862cf968d807497eef8#%E3%82%BF%E3%82%B0%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%AA%E3%81%84%E3%81%A7%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89)

ソースコードを読んでいただいた方はもうお分かりかと思いますが、私が実装した時点での人気タグ100個をGoファイル内で管理して、それを実行時に呼び出しています。
そのため、**私がこのツールを作成した当時の人気のタグ100個の中からランダムに選ばれる**形となっています。

実行時にリアルタイムで100個のタグを選択して〜、というのは勿論可能ですが、元々gofeed試したい目的、ということもあり、ここらへんも完全に横着しています。
あと、Qiita APIは認証していないとすぐに上限が来てしまうと思うので、そこらへんのことも考慮したくないという気持ちもありました。

## おわり
というわけで、もしよろしければ使ってみてください。
自分的にはこのツールのシンプルさが、ちょっとした空き時間と相性良くて、意外と時間が潰せるツールになりました。ビルドの待ち時間などにぜひぜひ。

実際に使ってみたところ↓
![qiita-tag-feed-reader-cli demo gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205976/42bae28e-c105-efdb-630a-22648ea6e00d.gif)