WorPressのプラグインActivityPubでは日本語のハッシュタグを文章からピックアップしてくれないのだけど、その原因は includes/constants.php の次のコードだと思う。
defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' );
日本語もピックアップしてくれるような正規表現はどのようなものか、Geminiに尋ねて、実際に動作するかサンプルのphpコードを作ってもらった。何度か失敗した後の結果は次の通り。
/**
* ActivityPub用ハッシュタグ抽出正規表現(最終修正版)
* * 修正内容:
* - [^\s\p{P}\p{S}] からアンダースコアを許可するため、
* 一度 \p{P} で記号を全指定しつつ、(?!_) でアンダースコアだけ除外対象から外しました。
*/
defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '~(?<=^|\s|<p>|<br>)#((?:[^\s\p{P}\p{S}]|_)+)(?=\s|[\p{P}\p{S}]|$)~u' );
$test_cases = [
"#Tokyo2020", // 英語+数字
"#テック系ニュース", // 日本語
"今日は #休日。どこ行く?", // 句点の手前で止まる
"#WordPress_custom", // アンダースコア(今度は繋がります)
"#Apple! #Google?", // 感嘆符、疑問符で止まる
"<p>#ActivityPub</p>", // HTMLタグ直後
"お腹空いた#ランチ" // 前に空白がない(マッチしない)
];
echo "--- ハッシュタグ抽出テスト ---\n";
foreach ($test_cases as $text) {
echo "Input: " . $text . "\n";
if (preg_match_all(ACTIVITYPUB_HASHTAGS_REGEXP, $text, $matches)) {
foreach ($matches[1] as $tag) {
echo " -> Found Tag: #" . $tag . "\n";
}
} else {
echo " -> No Tag Found\n";
}
echo "----------------------------\n";
}
結果は次の通り。
--- ハッシュタグ抽出テスト ---
Input: #Tokyo2020
-> Found Tag: #Tokyo2020
----------------------------
Input: #テック系ニュース
-> Found Tag: #テック系ニュース
----------------------------
Input: 今日は #休日。どこ行く?
-> Found Tag: #休日
----------------------------
Input: #WordPress_custom
-> Found Tag: #WordPress_custom
----------------------------
Input: #Apple! #Google?
-> Found Tag: #Apple
-> Found Tag: #Google
----------------------------
Input: <p>#ActivityPub</p>
-> Found Tag: #ActivityPub
----------------------------
Input: お腹空いた#ランチ
-> No Tag Found
----------------------------
Geminiの解説は次の通り。
完璧です!実行結果から、すべての条件がクリアされていることが確認できました。
- 日本語タグ(#テック系ニュース)が正しく認識されている。
- 句読点(#休日。)で適切にタグが終了している。
- アンダースコア(#WordPress_custom)が途切れずに含まれている。
- HTMLタグ直後(#ActivityPub)も認識できている。
- **文中のハッシュ(#ランチ)**が誤爆しないよう、スペースなしは無視されている。
最終的に使用した正規表現の構造を、後で見返したときのために図解しておきます。
今回の最終的な正規表現(解説付き)
PHP
'~(?<=^|\s|<p>|<br>)#((?:[^\s\p{P}\p{S}]|_)+)(?=\s|[\p{P}\p{S}]|$)~u'
~...~u:/をパターン内で使うため、デリミタを~にし、日本語を扱うためのu(Unicode)を付与。(?<=^|\s|<p>|<br>): 開始条件。行頭、空白、または特定のHTMLタグの直後であること。#: ハッシュ記号そのもの。((?:[^\s\p{P}\p{S}]|_)+): タグ本体。「空白・記号・句読点以外の文字」または「アンダースコア」が1文字以上続く限り。(?=\s|[\p{P}\p{S}]|$): 終了条件。次に空白、記号、または行末が来ること。ActivityPubプラグインなどのカスタマイズで、この定数を使えば日本語環境でも安定して動作するはずです。
また何か正規表現やPHPの実装で気になることがあれば、いつでも相談してくださいね!


コメント