【13日目】正規表現と最近できた落とし穴①【PythonでDiscordBOTを作ろう！】

# 正規表現？？？？　落とし穴？？？

> _正規表現とは、正規な表現です。_
> _つまり、正規な表現ということです。_

落とし穴については少し後で紹介します。

例えば、「猫」のメッセージに反応するBOTを作ってください。と言われたとします。
その場合、皆さんならどうするでしょうか。

## 一般的な例
まず、送られてくるメッセージに対して反応するため、`on_message`で`message`を取得して、`message.content`が猫どうかを判定します。
判定には`if`を使えばいいですね。

```py:main.py - async def on_message
@bot.event
async de on_message(message: nextcord.Message):
    if message.content == "猫":
        await message.reply("にゃーん")
```

こんな感じに。

しかし依頼主からこんなことを言われました。
> 猫て！
> 「ねこ」とか「ネコ」とか「ﾈｺ」にも対応せいや！

するとどうでしょう。

```py:main.py - async def on_message
@bot.event
async de on_message(message: nextcord.Message):
    if message.content == "猫" or message.content == "ねこ" or message.content == "ネコ" or message.content == "ﾈｺ":
        await message.reply("にゃーん")
```

だいぶ見にくくなりました。
しかし、更に依頼主から言われます。
> 「ﾈこ」とかも猫だからそれも反応してくれや

いやまぁ注文が多いってのは仕方ないですが...

これで、さっきと同じように「`message.content == "ねｺ"`」みたいなのを無限に追加してもいいんですけど...

**めんどくさいですよね！！！**

というわけで「正規表現」の出番です。

## 正規表現をつかうと

正規表現を使うには、デフォルトモジュールの`re`をインポートする必要があります。

とりあえず「猫」に反応させてみましょう。
```py:main.py - async def on_message
import re

@bot.event
async def on_message(message: nextcord.Message):
    if re.search("猫", message.content):
        await message.reply("にゃーん")
```

`re.search`は、第2引数の文字列を第1引数のパターンで判定します。
`search`は「検索」で、どこか一部分でも判定に合えばマッチオブジェクトを返し、まったく合わなければ`None`を返します。
`if`は、`None`または`False`でないようなオブジェクトとかであれば、基本的に`True`判定となって、そのまんま中のコードを実行します。

つまり、メッセージ本文に「猫」という文字が含まれていれば、中の`reply`が実行されるという訳です。

さぁこれで動かしてみましょう！！！

...

動きます？
動きませんよね。（ほかに設定をしていなければ）

これが、最近できた落とし穴`Message Content Intent`です。

通常は、`message.content`に、ちゃんとメッセージ本文が送信されますが、ちゃんと設定を行わないと`message.content`が常に空文字になります。

_ﾝｼﾞｬﾊﾝﾃｲﾃﾞｷﾝﾔﾝｹ!_
というわけでちゃんと設定を説明するので！

## `Intent`の有効化
`Intent`（インテント）とは、おおざっぱに言うと...なんでしょう...Discord側に、この機能使うよ～！みたいなのを説明するようなあれでしょうか...？

しかし、一部のintentはセキュリティー上の観点とかなんか色々から、設定を行わないと使用できません。
というわけで、まずは[Discord Developer Portal](https://discord.dev)に行きましょう。

左からApplicationを選択して、自分のBOTを選択します。
左のメニューからBotを選択して、Botページに行きましょう。

すると、少し下に`Privileged Gateway Intents`という項目があると思います。
これが、intentの設定です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1107984/97939270-fc17-a3b6-ef06-ca11ae6b6982.png)

書いてあることを訳すと、「Gateway Intentの中には、BOTが認証されている場合は承認を必要とするものがある。あなたのBOTが認証されていないなら、ここから有効化出来るよ」と書いてあります。

認証...？となった方もご安心ください。
BOTの認証については最終日に紹介したいなと思っております。

### 有効化しよう

オンオフスイッチが3つあります。
上から「Presense Intent」（Discord Presenseを取得する時とかに必要なインテント）「Server Members Intent」（サーバーのメンバー数を取得する時とかに必要なインテント）「Message Content Intent」（メッセージ本文を取得する時とかに必要なインテント）となります。
考えるのがめんどくさいので全部チェックを入れましょう！！♪
すべてチェックを入れたら、下の「Save Changes」を押しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1107984/989a38bc-2612-6a6e-02d3-93ff332d7684.png)

そしたら次にコード修正を行います。

```python:main.py
intents = nextcord.Intents.all()
intents.typing = False

bot = commands.Bot(intents=intents)
```

`bot = commands.Bot`の部分を修正します。
`nextcord.Intents`に色々なインテントの関数があります。
これの`all`（すべてのインテントをつっこんだもりもりインテント）から、`typing`を引いたものを使います。
`typing`というのは、「○○が入力中...」のインテントです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1107984/fd96e5fd-2190-e6e9-4fd6-b0a078e6d7f3.png)
あまり詳しくはわかりませんが、`typing`を`True`にしてると重くなるらしいです。

## 修正できたかな？

とりあえずコードを確認してみましょう。

```py:main.py
import re
import nextcord
from nextcord.ext import commands

intents = nextcord.Intents.all()
intents.typing = False

bot = commands.Bot(intents=intents)

@bot.event
async def on_ready():
    print(bot.user.name)

@bot.event
async def on_message(message: nextcord.Message):
    if re.search("猫", message.content):
        await message.reply("にゃーん")

bot.run("TOKEN")
```

とりあえず、これで起動させてみましょう。
そして「猫」と送ってみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1107984/98b4258a-1e82-f27e-08bf-a7086245b1ef.png)

とりあえずこれで「猫」には反応しますね。


# 次回予告

文量が多くなってしまいそうなので、一旦ここで切らさせていただきます。
次回はこれの続きです！
というわけで、今日の記事はここまでです。 もしよろしければ記事へのいいねをして、次回記事をお楽しみに！