絵文字が含まれるファイルを再帰的にgrepしたい

英語/日本語で調べたけど中々見つからなかったので、同じようなことをやりたい人のご参考になれば嬉しいです :pray: :sparkles: 

## :three: 行まとめ

- 絵文字を [Font Awesome](https://fontawesome.com/icons) に置き換えたい! :bulb: 
- 絵文字を含むファイルってどこだっけ...? :sweat_drops: 
- 再帰的に絵文字を探す `emoji-search` を書いてみた! :wrench: :dash: 

## :mag: `emoji-search` の実行例 

例えば[未踏ジュニア](https://jr.mitou.org/)の公式Webサイト ([:octocat: mitou/jr.mitou.org](https://github.com/mitou/jr.mitou.org/)) のルートディレクトリで `emoji-search` を実行すると、次のような結果が得られます。

```bash
╭─○ yasulab ~/jr.mitou.org
╰─○ emoji-search
alumni.md: 🆕 今年度より採択開始!
guideline.md: ※ 2021年度の応募は3月上旬から受け付ける予定です。 🙇‍
README.md: どの箇所を更新するにせよ、Webブラウザが一番簡単だと思います...!! 😆
_site/README.md: どの箇所を更新するにせよ、Webブラウザが一番簡単だと思います...!! 😆
_site/guideline.html: ※ 2021年度の応募は3月上旬から受け付ける予定です。 🙇‍
_site/download.html: 提案書の準備ができたら応募フォームへ! 😆
_site/download.html: ※ 2021年度の応募は3月上旬から受け付ける予定です。 🙇‍
mentors.md: 🆕 今年度より採択開始!
download.md: 提案書の準備ができたら応募フォームへ! 😆
download.md: ※ 2021年度の応募は3月上旬から受け付ける予定です。 🙇‍
```

## :gem: `emoji-search`コマンドの中身

当初はシェルスクリプトのgrep/findなどで書こうとしたのですが、簡単ではなさそうだったので断念 :sweat: 

**標準ライブラリだけで書きたい**なーと思って色々試したところ、Ruby で書くのが早そうだったので、結果として下記のようなコードになりました。コメントも付けてみたので、コードを読むご参考になれば! :pray: (grepコマンドは使っていませんがgrepっぽい見た目に近づけています)

```ruby
# Binaryファイルを弾くよ
require "open3"
def is_text_file?(filename)
  file_type, status = Open3.capture2e("file", filename)
  status.success? && file_type.include?("text")
end

# 絵文字を探していくよ
Dir.glob('**/*').each do |filename|
  # `.git`ディレクトリやBinaryファイルを調べると遅くなるのでスキップ
  next if filename.start_with? "."
  next unless is_text_file? filename

  File.open(filename) do |f|
    f.each_line do |line|
      # BMP 外の文字が含まれるか否かで探して、見つけたら出力するよ
      # 詳細: https://qiita.com/yusukeyamane/items/79764e36cc5bd89bc9a4#comment-e879ba227ab95b006017
      puts("#{filename}: #{line}") if line.match?(/[^\u0000-\uFFFF]/)
    end
  end
end
```

あとは bash/zsh などで `emoji-search` をエイリアスに設定して、

```bash
alias emoji-search="ruby /path/to/emoji-search.rb"
```

調べたい場所で `emoji-search` すると完成です :book: :mag: :dash: 今回は標準ライブラリのみで書いているので、Ruby が入っていれば大体使えるはず...!!

皆さんの絵文字ライフが快適になれば嬉しいです! :laughing: :sparkles: 

## :white_check_mark: オマケ: なんで `/\p{Emoji}/` を使わないの?

他の[Qiita記事のコメント欄](https://qiita.com/yusukeyamane/items/79764e36cc5bd89bc9a4#comment-e879ba227ab95b006017)で @scivola さんが解説されていますが、予想以上にマッチしてしまっていたため別のアプローチを採りました :sweat:

例えばコードの一部を次のように変更し、

```diff
- puts("#{filename}: #{line}") if line.match?(/[^\u0000-\uFFFF]/)
+ puts("#{filename}: #{line}") if line.match?(/\p{Emoji}/)
```

再度 `emoji-search` コマンドを実行すると、 `#` を含む部分なども引っかかってしまいました :eyes: :sweat_drops:(Ruby 2.7.2 で実行) 

```bash
╭─○ yasulab ~/jr.mitou.org
╰─○ emoji-search

... (省略)

download.md: ## 提案書テンプレート {#template}
download.md: 提案書のテンプレートを以下からダウンロードして、PDFに変換後、[応募フォーム](#ready)からアップロードしてください。
download.md: <a href="https://jr.mitou.org/assets/other/mitoujr_application_2021.zip" class="button">Word・Pages を使う</a>
download.md: <a href="https://docs.google.com/document/d/1hjDYf2DbFBkXLyrAl9HKKc9sS40XbZ_iN2j-HKZXD9g/edit?usp=sharing" class="button" target="_blank">Google Docs を使う</a>
download.md: ## 提案書サンプル {#sample}
download.md: <a href="https://jr.mitou.org/assets/other/2020_application_samples.zip" class="button">過去の提案書を見る</a>
download.md: ## 準備できた? {#ready}
download.md: <p class="text-center">提案書の準備ができたら応募フォームへ! 😆</p>
download.md: ※ 2021年度の応募は3月上旬から受け付ける予定です。 🙇‍
```

他の正規表現もいくつか試したところ、今回の用途に限って言えば[コメント欄](https://qiita.com/yusukeyamane/items/79764e36cc5bd89bc9a4#comment-e879ba227ab95b006017)にある `/[^\u0000-\uFFFF]/` だと欲しい情報が得られたので、今回はその正規表現を使っています :pray: :sparkling_heart: 

絵文字は奥が深いですね... :eyes: :thought_balloon: