Ankiで重複するカード、記憶を頼りに手作業でタグ付けしてたら大変すぎてClaude Codeに任せてみた話

この記事でわかること:AnkiConnect(Ankiをプログラムから操作できるアドオン)経由でClaude CodeがAnkiを直接操作する方法。異なるデッキに分かれている重複のカードを記憶を頼りに手作業でやっていた重複カードチェックをAIに任せてみた実例。カードの表面にブラウザの記事のコピペで作った単語カードはたまにHTMLタグ混入があって、Anki独自の重複カードを選定する機能があるんですが、それだと禁止されなかった見逃されていた重複の見つけ方。

重複カードがあると再度学習することになって効率が落ちるので整理しようと立ち上がりました。

スポンサーリンク

8年分のAnkiデッキ、重複がどれだけ埋もれてるかわからなくなっていた

Ankiを8年近く使ってると、単語ってどんどん増えるんですよね。また使用している単語デッキも今数えたら13個ありました。その中でも「英語 備忘」「DUO」「DUO派生語」「EX1級」の4つが今のメイン学習デッキなんですけど、この4つの生まれ方がそれぞれちがっています。

自分のデッキです。 あまりつかってないものもありますが。。。

そもそもの英語学習のスタートは、DUOのカードを全部まるっと取り込むところから始まりました。これはAnkiの共有、クラウド、ユーザ同士がカードデッキを作ってアップロードもできるし、誰でもその他の人が作ったデッキをダウンロードできて使えると言う素晴らしいShareDeckというAnkiの中にあるんですけど、そのShareDeckにDUOの3.0の単語がもともとあったんです。

https://ankiweb.net/shared/decks?search=Duo3.0

見た感じDuo3.0の7つぐらい今ShareDeckがありますがここから自分に合ったものも普通に自分の暗記に取り込んで使用する事ができるんです。誰かが作ったものなので、多少間違いとか誤字とかもありましたが。

そこからDUO3.0をやり込んだ後に、次にDuo3.0の本から派生語の単語を手入力で登録しながら、Duo派生語デッキを作っていきました。

そして、英会話とか、外国の友達とかができて会話する事が多くなったり、英語の記事を読んだりしてわからない単語とか良い表現を覚えたいなと思ったときにAnkiに手入力で追加していく「英語備忘デッキ」も作りました。基本的に自分の場合はこの英語備忘というところにわからなくなった単語とか覚えたい単語、新聞の記事とか英会話で指摘されたこととか、何でも入れれるようなデッキに定義付けました。

この2つ、Duo3.0のShareDeckでいれたもの以外のDuo派生後デッキと英語備忘デッキは実は基本手入力だったので、重複カードがそもそも生まれない仕組みになってたんです。「あ、この単語DUOにすでにあるな」と思ったら備忘には入れないし、逆に「これこの前備忘で見て登録したやつだ、スキップしよう」みたいな感じでDuo派生語にはいれないし、頭の中でチェックしながら育ててきたデッキだったんですよね。

ところが、英検準1級に受かったあとに買った単語、英検1級EX、これを丸ごとカメラでパシャパシャ撮って、AIで全てCSV化して新しくAnkiにEX1級デッキというのを作って、一括でインポートしたんです。英検準1級の時は複数の単語帳とか問題集からわからない単語を手入力で入れていたので、かなりの年月がかかりました。ほんとに3年ぐらいかかったと思います。だけど、AIの進化はほんとにすごくて、英検1級EXの単語帳は1ヵ月もたたないうちに、全てAnkiにインポートできました。

ただ、CSVで一括インポートしたので重複の除外は一切しなかったです。1冊まるごと機械的に流し込んだので大量の重複カードが生まれてしまって。まずはAnkiの重複を調べて、タグをつけれる機能があるので表のカードの単語で完全一致のものは重複を調べられることができました。ただ冒頭でも触れたように今まで手入力でブラウザでコピペして貼り付けできたので、中にはHTMLのたぐとかCSSとか入ってるものもあったりして、これが重複タグがつけれずにいました。一つ一つ目で確認していって、これは他のデッキにあったなと省いていましたが、かなり量があったので何か良い方法ないかなと。

重複したままだと同じ単語を2回学ぶことになるし、かといって復習中に「あ、これ重複だ」って気づくたびにいちいちサスペンドしてたら、めんどくさくて仕方ない。なので「もう一気に重複カードをサスペンドしよう!」と腰を上げて、CLAUDE君にお願いしてみることにしたんです。

そもそも、Claude CodeってAnkiと繋がるの?

そうなんです。ClaudeCodeはいろいろなアプリをつなぐことができるので、AnkiもAnkiのソフト自体にAnkiコネクトと言うプラグインを入れておけば、Claudeから編集したり追加したり柔軟に便利な操作が可能になるんです。Claudeで新しいチャットを開いて、「ここから私のAnkiってつなげましたよね?」ってきくとCLAUDE君、curlでこんなの叩き始めて。

curl -s -X POST http://localhost:8765 -d '{"action":"version","version":6}'

返ってきたのが

{"result": 6, "error": null}

これ、AnkiConnect(Ankiをプログラムから操作できるアドオン)がlocalhost:8765でAPIを立ててくれてて、そこにcurlで話しかけてるだけなんです。チャットで喋るだけで、裏でローカルのAnkiアプリに直接コマンドが飛んでるっ( ゚д゚)

まずデッキ一覧を見せてもらったら、想像以上に細かく出てきた

13デッキ全部の枚数・新規/学習中/復習の内訳が一発で表になって出てきました。

デッキカード枚数内訳(新規/学習中/復習)
EX1級2,834枚新規2・学習中21・復習78
英語 備忘6,558枚新規0・学習中22・復習158
DUO(English_Duo_Tango)2,566枚新規0・学習中1・復習17
DUO派生語2,842枚新規0・学習中3・復習36

手でAnkiのDeck List画面を1個ずつクリックして説明かねて数えなくていいの、単純に楽ですよね。自然言語でやってくれるのほんと楽です。 

duplicateタグの現在地を確認(でもまだ何もしないでねと念押し)

ここで私、CLAUDE君に釘を刺しました。「まずタグをみれますか?まだなにもしないでみるだけでいいです」って。だって、いきなり大量のカードを勝手に変更されたら困るじゃないですか。

で、findCardsというAPIでこんな感じのクエリを投げてもらいました。

curl -s -X POST http://localhost:8765 -d '{"action":"findCards","version":6,"params":{"query":"deck:\"1英語学習::EX1級\" tag:duplicate"}}'

結果、EX1級デッキ全体2,834枚のうち:

  • duplicateタグあり:844枚
  • うち停止(サスペンド)済み:809枚
  • duplicateタグはあるのに停止されてない:35枚

今まで英語学習で出会った単語たちと比較してEX1級に844枚完全一致の重複があって、これはAnkiの機能でduplicateのタグをつけたものですね。

そのあと完全一致じゃないもの、たとえば accentuate が2枚あれば完全一致でAnkiだけでサスペンドできるんですが、 英語備忘デッキとかには単語の後にaccentuate … みたいに、Duoやってる人ならわかると思いますが私も最初Duoから単語学習はじめて他動詞には … を付けるようになってしまったので。なにせ手作業ですべて登録してきたので・・・・(;´∀`) 6000枚以上もあるんですね・・・ コツコツの作業が最強とわかる瞬間です。 で、例えばこの2つのカード、

accentuate

accentuate …

だと、Ankiから重複とみなせないんです。 なので自分で目で見て、重複してるものかそうじゃないかを英検1級EXのDeckから重複のタグ付けをしようとおもって。

で途中までしてそのままわすれていたのか、サスペンドしてない、タグだけついてる35枚、見た瞬間「あ、これ自分でタグだけ付けてサスペンドし忘れてたやつだ」ってすぐわかりました。

なので「三十五枚はわたしが自分でつけたものなのでサスペンドしてください」とお願いして、そこはサクッと処理してもらいました。

備忘とEX1級で「単語の登録の仕方」がそもそも違った

ここからが今回の核心なんですけど。残りの未チェック分を見たいとお願いしたとき、CLAUDE君に一つ説明したんです。

「備忘やDuoには、他動詞には … とか ~ がはいっています。最初そのように登録してきたので。でもEXは単語だけになってます」

実際にサンプルを出してもらったら、こうでした。

英語 備忘デッキ(一部)

pass one's …
at the age of ~
help oneself to (飲み物、食べ物)
love 〜ing
I suck at ...

EX1級デッキ(一部)

squander
flimsy
incision
lethargic
pinnacle

見事に登録の仕方が違うんですよ。備忘は他動詞の目的語を...~で表現する“型”登録、EX1級は単語だけのシンプル登録。つまり単純な完全一致チェックだと、この表記ゆれのせいで拾いきれない重複があるんです。

上記で説明したみたいな、inundate(水浸しにする、殺到する)という単語、EX1級にはinundateだけで登録されてるのに、備忘にはinundate ...って...付きで登録してるので、見た目はほぼ同じ単語なのに、文字列としては完全に別物なので、単純な完全一致チェックだと素通りしちゃうんですよね。

ちなみに~が付いてるものも探してみたんですけど、at the age of ~みたいに複数の単語からなるフレーズがほとんどで、単語1個だけの重複ペアはあまり見つかりませんでした。これはこれで「フレーズごと登録してるものは、そもそも単語単体のEX1級とは比較しづらい」という別の課題だなと気づいたんですよね。

スクショで発覚したHTMLタグ混入事件

さらにもう一個問題が出てきました。Ankiのブラウザ画面のスクショを見せたんです。「pharmacist」というカードで、画面上はふつうにpharmacistって表示されてるんですけど、実際のフィールドの中身(コード部分)を見たら

<em><strong>pharmacist</strong></em><br>

ってなってたんです。他のサイトから単語をコピペしたときに、HTMLタグごと紛れ込んでたっぽくて。カード表示は普通の単語なのに、中身はコードまみれ。これ気づかなかったら永遠に重複判定から漏れ続けるやつです。

正規化ロジックを組んでもらった

なので「まずは実行せず、重複だけリストにばっとだせますか?」とお願いして、以下のルールで突き合わせてもらいました。

  • HTMLタグ・[sound:...](音声タグ)を除去
  • ()・()内の注釈を除去
  • ... ~ を除去
  • 前後の空白を消して小文字化
  • 正規化した文字列が完全一致した場合だけ重複候補にする(部分一致はNG)

ここも念のため「もし EX put、備忘 put run on とかなら重複じゃない。完全同じ単語で重複を調べてほしいです」と具体例つきで指定しました。実際に使われたPythonコードがこちらです。

import json, re, subprocess, sys
def ankiconnect(action, **params):
    payload = json.dumps({"action": action, "version": 6, "params": params})
    result = subprocess.run(
        ["curl", "-s", "-X", "POST", "http://localhost:8765", "-d", payload],
        capture_output=True, text=True
    )
    return json.loads(result.stdout)["result"]
def strip_html(text):
    text = re.sub(r'\[sound:[^\]]*\]', '', text)
    text = re.sub(r'<[^>]+>', '', text)
    text = text.replace('&nbsp;', ' ').replace('&amp;', '&').replace('&lt;', '<').replace('&gt;', '>')
    return text
def normalize(text):
    t = strip_html(text)
    t = re.sub(r'\([^)]*\)', '', t)
    t = re.sub(r'([^)]*)', '', t)
    t = t.replace('…', '').replace('...', '').replace('~', '').replace('〜', '')
    t = re.sub(r'\s+', ' ', t).strip().lower()
    return t

備忘・DUO・DUO派生語の全11,678語(正規化後のユニーク数)と、EX1級の未チェック1,990枚を1個ずつ突き合わせてもらった結果──307件が完全一致で見つかりました。

リストをopenでチェック→「完璧ですね」

見つけた307件はmarkdownの表に整形してファイルに保存してもらって、「open してください 一度チェックします」でFinderから普通に開いて目視確認。

中身を見て、思わず「完璧ですね」って言っちゃいました。

きれいに重複している単語だけ持って来てくれたのでこの辺、Claude君が優秀な分野なのかなと。

他のデッキ、本当に無傷ですよね?と念押し確認

タグ付けをお願いする前に、一個どうしても確認したかったことがあって。「Duoとかほかのデッキのコードとかカラーコードがはいっていたものはいじりませんよね?」って聞いたんです。

正規化処理ってHTMLタグとか消してるので、まさか元のカードまで書き換えられてないよなって、当然の不安じゃないですか。答えは「正規化はPython側の一時コピーに対してだけやってて、備忘・DUO・DUO派生語には読み取り専用のnotesInfoしか呼んでない」とのこと。ちゃんと確認してから次に進めたので、ここは安心して任せられました。

307件をEX1級側だけにタグ付け+サスペンド実行

「さっき重複リスト作ってくれたものにDupulicate タグつけてサスペンドして、EX1級意外のカードは無傷のままでお願いします」とお願いして実行。

  • addTagsでEX1級側の307ノートにduplicateタグ
  • suspendでその307枚のカードだけ停止

結果、EX1級のduplicateタグ計は 809+35+307=1,151枚に。他3デッキは操作前後で数値が完全に一致していて、無傷が確認できました。下記、カード枚数の統計スクショですが1個増えてる・・・・

でも総数15147枚、サスペンドは1152枚になってました。

まさかの伏兵、謎の古いduplicateタグ発見

ここで「他デッキにもDuplicateがあるんですか?」と聞いてみたら・・・出てきたんですよ、謎のタグが。

  • 英語 備忘:624件
  • DUO:133件
  • DUO派生語:138件

自分で付けたことすら覚えていないduplicateタグが、以前からずっと存在してたんです。「なんでついたかおぼえてません」って自分の作業なのに他人事みたいなコメントしか出てこなくて( ̄∇ ̄)。leechタグ(Anki標準の「間違え続けてるカード」用タグ)と一緒に付いてるものも多かったので、たぶん昔別の目的でやった何かの名残だと思います。

サスペンド方針をはっきり言葉にした

ここでちゃんと方針を言葉にしました。

「基本備忘、DUO,DUO派生 はサスペンドしないようにしてEX1級からはぶくようにしたいですね(学習記録が真っ白なのはEX1級の方なので)」

考えてみれば当たり前で、備忘・DUO・DUO派生語は何年も復習してきた学習履歴があるデッキ、EX1級は真っ新なデッキ。重複してるなら、履歴がまっさらな方を除外すればいいだけなんですよね。

確認してもらったら、備忘・DUO・DUO派生語の古いduplicateタグ895件は、実はどれもサスペンドされていなかった(0件)。すでに希望通りの状態になってました。ただ、DUO派生語の中に1枚だけ、duplicateタグと無関係な理由でサスペンドされてるカード(”shrinkage”)を発見。

「あと一枚もサスペンドしたおぼえはないので、偶然はいっちゃったんだとおもいます 戻しておいてください」

ということで、これも身に覚えのない事だったみたいです。

不要タグの削除、誤サスペンドの復旧

じゃあこの意味不明な895件のタグ、どうするか。

「その3つのデッキの重複タグは必要ないですよね?」

と聞かれて、機能的には確かに何も動かしてない(サスペンド0件)ラベルなので、削除するか残すかの2択を提示してもらいました。「削除する(推奨)」を選んで実行。

  • 3デッキのduplicateタグ895件をremoveTagsで全削除
  • “shrinkage”カードをunsuspendで復旧

これで備忘・DUO・DUO派生語は完全にクリーンな状態に戻りました。

「未チェック」の意味をすり合わせ、完全一致だけで十分と結論

最後にもう一段階すり合わせがありました。Claudeが残り未チェック1683枚ですみたいな事をいっていたので、

「あとのこりの未チェックのEX1級の意味を教えてください」

と聞いたら、実は「未チェック」という呼び方が誤解なことが判明。EX1級2,834枚=タグ済み1,151枚+残り1,683枚で、この1,683枚はチェック済み・完全一致の重複が見つからなかった枚数だったんです。

「完全一致のはのぞけたんですよね?」

と確認して、数字がぴったり合うのを見て安心しました。

そのうえで最終ルールを伝えました。

「基本、完全一致だけでいいです。同じ語彙の形容詞、名詞、副詞とかが、別々のカードにあっても、1つのカードの中で、名詞の意味はこれ、形容詞はこう、という1つのカードに複数の品詞があっても私のルールはOKです」と。

品詞違い(acrimony と acrimonious みたいな派生語)まで拾いにいく“ゆるいマッチング”は今回あえてやらないという結論です。精度を上げようとすると誤検出も増えるので、そのトレードオフを理解した上で「完全一致だけで十分」と判断できました。

まとめ:AIがローカルのAnkiを直接触れるって、思った以上にすごかった

正直、Claude Codeって「コードを書いてくれるツール」だと思ってたんです。

でも今回わかったのは、ローカルで動いてるアプリにAPI経由で直接コマンドを送って、データを読んだり書いたりできるってことなんですよね。しかも「まだ何もしないで見るだけでいい」「他デッキは無傷ですよね?」って何回も確認しながら進められたので、1万枚超えのデータを一括処理するのも安心して任せられました。

品詞違いまで含めた“ゆるい”重複チェックはまた今度、必要になったらやってみようかなと思ってます。とりあえず今回は、8年分放置してた重複への引っかかりが1個スッキリした感じです♪( ´▽`)

今日学んだの英語表現(B2〜C1)

一応英検1級目指してるスーツマンのこの記事のトピックから使えるフレーズをAIがピックアップ。

① squander(=浪費する)

She squandered all of her savings on overpriced skincare.

「金・時間・機会などを無駄遣いする」という意味。EX1級デッキに入ってた単語で、今回の重複チェックのサンプルにも出てきました。

② mesmerize(=魅了する、うっとりさせる)

The performance mesmerized the entire audience.

「催眠術にかけたように引き込む」というのが語源のニュアンスで、ただの「面白い」より強い没入感を表すときに使います。

③ propensity(=(好ましくない)傾向、性癖)

He has always had a propensity for violent behavior.

好ましくない方向のクセ・傾向を指すときによく使われる単語。似た意味のtendencyより少し硬い響きです。

(この記事で実際にAnkiカードとして登場した単語からピックアップしました)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です