Googleスプレッドシートで康煕部首をチェックしたいだけ

# ⾕なのか谷なのか問題を解決する
ぱっと見ただけではわからないのですが、上記の「谷」はそれぞれ別の文字になっています。
コードブロックで見ると、少しだけ違うのがわかると思います。（`⾕なのか谷なのか`）
※すみませんスマホブラウザから見たら全然違いがわからなかったです……フォントによって見え方が変わるのでご了承ください……
この「⾕」の文字は康煕部首（こうきぶしゅ）と呼ばれるもので、フォントの種類によりますが、見た目だけでは判断がつかないので、名前の重複チェックなどをする際にうまくチェックできない場合が発生します。

## 康煕部首（こうきぶしゅ、英語: Kangxi Radicals）とは
康煕部首は、中国の漢字字典、『康煕字典こうきじてん』に示された漢字の分類に用いられる部分字形で、通常の漢字と同じように見えてもこれらはあくまでも部首を表すもの。そのため、単漢字の「谷」と康煕部首の「⾕」は全く異なる文字となります。
（日本語においては使うシチュエーションがあまりない文字といえそうです）

# 実際にチェックする関数
※Googleスプレッドシートでは動作しますが、Excelの場合は動作しません。
（Office365であればTEXTSPLITの関数などもあるので似た関数の組み合わせで、実装は可能かも）
```vb
=COUNTIFS(INDEX(CODE(SPLIT(REGEXREPLACE($A1,"","_"),"_"))),">="&12032,
INDEX(CODE(SPLIT(REGEXREPLACE($A1,"","_"),"_"))),"<="&12245)>0
```
下記のサイトを参考に康煕部首のコード値の範囲を12032～12245として、文字列を配列にしてコード値が康煕部首の文字コードの範囲内である場合をカウントすることでチェックを行うようにしました。
[KangXi Radicals | UTF-8 Icons](https://www.utf8icons.com/subsets/kangxi-radicals)
`SPLIT(REGEXREPLACE($A1,"","_"),"_"))`の部分は文字列を配列化にするために、
`REGEXREPLACE(文字列, パターン, 新しい文字列)`で空文字を一度アンダースコアに変換してから、
`Split(文字列 , 区切り文字)`で変換したアンダースコアを基準に文字列を配列に変換。
配列の文字を1文字ずつコード値に変換したあと、カウントを取っていく形にしています。

# GASで組むならこう
なお、GAS関数でGoogleスプレッドシートに利用する場合、条件付き書式の条件としては利用できないようだったので、今回は関数のみ利用したものを利用する形にしました。
```javascript
/**
 * chkNgCode
 * 文字列の中に康煕部首（こうきぶしゅ）が含まれている場合にTrueを返却する
 * return Boolean
 */
function chkNgCode(targetStr) {
  let ret_val = false;
  let buf_arr = targetStr.split(''); // 文字列を分割

  for (let charactor of buf_arr){
    let targetCode = charactor.codePointAt(0);
    if (targetCode >= 12032 && targetCode <= 12245) {
      ret_val = true;
      break;
    }
  }
  return ret_val;
}
```


# ChatGPTくんを使ってみる
せっかくなので、よりよい方法があるなら見直したいと思いChatGPTで康煕部首のチェック方法を聞いてみました。
以下、いろいろと投げてみたものの、**結果として実用可能な関数は返ってこなかった**です。苦笑
おそらくより詳細に設計してあげたものを投げかけるORより簡単な関数、あるいはよく利用されるような関数を組むという場合には置き換え的に威力を発揮するような気がします。（おそらくはデータ量が少ないのだろうと思います。）
あるいは私の聞き方が悪かった可能性もあります。


## 文字列の中に康煕部首が含まれている場合にTrueを返却するExcel関数を組んでください

```vb
Function ContainsKangxiRadical(str As String) As Boolean
    Dim kangxi As String
    kangxi = "⺅⺮⺑⺘⺡⺨⺾⻌⺹⺷⻏⺻⻖⺝⻆⺣⺧⺼⻂⺤⺪⻐⺰⻛⺳⻗⺷⻝⺮⻌"
    For i = 1 To Len(str)
        If InStr(kangxi, Mid(str, i, 1)) > 0 Then
            ContainsKangxiRadical = True
            Exit Function
        End If
    Next i
    ContainsKangxiRadical = False
End Function
```
Function名は参考になるな～と思いつつ、VBAで組んじゃうあたりの発想は「まぁわかる。そうなるよな」と共感してしまいました。笑
ただ、この時点で康熙部首が明らかに足りていない＆直接指定しているので、ちょっとなぁ……と個人的にモヤる。

## vbを用いることなくExcel関数のみを用いて上記を満たしてほしい
```vb
=IF(SUMPRODUCT(--ISNUMBER(FIND(MID("⺅⺮⺑⺘⺡⺨⺾⻌⺹⺷⻏⺻⻖⺝⻆⺣⺧⺼⻂⺤⺪⻐⺰⻛⺳⻗⺷⻝⺮⻌",
 ROW(INDIRECT("1:"&LEN("⺅⺮⺑⺘⺡⺨⺾⻌⺹⺷⻏⺻⻖⺝⻆⺣⺧⺼⻂⺤⺪⻐⺰⻛⺳⻗⺷⻝⺮⻌"))),1),A1)))>0,TRUE,FALSE)
```

ChatGPT君の中ではこれらの30文字が康熙部首であることはゆるぎない模様。
こちらはExcelでも動きました。（Ver：Office365）もしかしたらこっちの関数の組み合わせから流用して作ったほうが汎用性高いかも？
ちなみに「⾕」が含まれていないのでチェックに引っかかってくれませんでしたが、逆に言えば「⾕」を含めたら動作しました。惜しい。
網羅してよ～ということで下記の投げかけを追加。


## 上記の場合、康煕部首をすべて網羅していないので、康煕部首のUnicodeの範囲内の文字が文字列に含まれている場合のExcel関数を組み直してください

```vb
=IF(SUMPRODUCT(--ISNUMBER(FIND(UNICODE(MID($A1,ROW(INDIRECT("1:"&LEN($A1))),1)),
 UNICODE("⺀"):UNICODE("⿕"))))>0,TRUE,FALSE)
```

なるほどね。（なるほどね？）
ぱっと見、網羅できてそうで網羅できていない関数になっていました。
あとこっちだとExcelに入れても動作しません……
もっと細かく指定してあげたらいいのかもだけど、だったら調べて自分で組んだほうが早いな～という気持ちになりました。
今後データ量が増えたら、より精度も高くなるのだろうか？

# 雑感
ChatGPTが一挙に持て囃されていることもあり、どれほどのもんじゃいと思って使ってみたところもあるのですが、ある程度頭で「こういうことがしたい」というときは自分で調べて組んでみたほうが低コストだな、というのが今のところの感想です。
また、Excelで複雑な関数が組んであるんだけど、具体的にどういう動作をしているかわからないな…というときは貼り付けて聞いてみると仕様を返してくれるので、そういった活用方法はありかも。
ただ、引用元が明示的ではないので、公式リファレンスを見ないと不安なんじゃ、という場合はやっぱり不向きかも。
（そういう意味でも、引用元も出してくれるタイプのAIのほうが需要は高いかも）