はじめに
Twitter API を使って投稿を自動化する際、ツイートの文字数カウント は避けて通れない重要なポイントです。
本記事では、Twitter の文字数カウントの仕様 を正しく理解し、PHP(Laravel)と TypeScript で実装する方法 を詳しく解説します。
✅ Laravel の独自バリデーションを作成
✅ TypeScript でリアルタイムチェック(Zod を使用)
✅ PHPUnit で Laravel のバリデーションをテスト
✅ Jest で TypeScript のテストコードを作成
Twitter の文字数カウント仕様
Twitter では、1ツイートの最大文字数は 280文字 ですが、以下のルールに従う必要があります。
- ✅ 通常の文字(英数字・ひらがな・カタカナ・漢字) → 1文字 = 1カウント
- ✅ 全角記号や Emoji などの特殊文字 → 1文字 = 2カウント
- ✅ URL(リンク) → 1つの URL は 23 文字としてカウントされる
このルールに基づき、実装を進めます。
1. PHP で Twitter 文字数カウントを実装
まずは PHP で Twitter の文字数カウントロジックを作成します。
PHP 実装コード
function countTwitterCharacters($text) {
$url_pattern = '/https?:\/\/[^\s]+/';
$url_count = preg_match_all($url_pattern, $text, $matches);
// URL を 23 文字換算
$text = preg_replace($url_pattern, '', $text);
$char_count = $url_count * 23;
// 文字の長さをカウント(全角・Emoji は 2 カウント)
foreach (mb_str_split($text) as $char) {
$char_count += (mb_strlen($char, 'UTF-8') > 1) ? 2 : 1;
}
return $char_count;
}
2. Laravel で Twitter 文字数バリデーションを実装
カスタムバリデーションの作成
php artisan make:rule TwitterTextLength
生成された app/Rules/TwitterTextLength.php
に実装します。
カスタムバリデーションの実装
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class TwitterTextLength implements Rule
{
public function passes($attribute, $value)
{
return $this->countTwitterCharacters($value) <= 280;
}
public function message()
{
return 'ツイートの文字数が280文字を超えています。';
}
private function countTwitterCharacters($text)
{
$url_pattern = '/https?:\/\/[^\s]+/';
$url_count = preg_match_all($url_pattern, $text, $matches);
$text = preg_replace($url_pattern, '', $text);
$char_count = $url_count * 23;
foreach (mb_str_split($text) as $char) {
$char_count += (mb_strlen($char, 'UTF-8') > 1) ? 2 : 1;
}
return $char_count;
}
}
PHPUnit でバリデーションをテスト
use App\Rules\TwitterTextLength;
use PHPUnit\Framework\TestCase;
class TwitterTextLengthTest extends TestCase
{
public function test_valid_tweet()
{
$rule = new TwitterTextLength();
$this->assertTrue($rule->passes('tweet', 'これはテストです!'));
}
public function test_tweet_with_url()
{
$rule = new TwitterTextLength();
$this->assertTrue($rule->passes('tweet', 'https://example.com')); // 23文字としてカウント
}
public function test_tweet_exceeds_limit()
{
$rule = new TwitterTextLength();
$this->assertFalse($rule->passes('tweet', str_repeat('あ', 150))); // 300文字
}
}
3. TypeScript で Twitter 文字数カウントを実装
TypeScript 実装コード
function countTwitterCharacters(text: string): number {
const urlPattern = /https?:\/\/[^\s]+/g;
const urls = text.match(urlPattern) || [];
text = text.replace(urlPattern, '');
let charCount = urls.length * 23;
for (const char of Array.from(text)) {
charCount += char.length > 1 ? 2 : 1;
}
return charCount;
}
4. TypeScript で Zod を使ったバリデーション
Zod を使うと、TypeScript で直感的なバリデーションができます。
Zod バリデーションの実装
import { z } from "zod";
const tweetSchema = z.string().refine((text) => countTwitterCharacters(text) <= 280, {
message: "ツイートの文字数が280文字を超えています。",
});
// テスト
console.log(tweetSchema.safeParse("これはテストです! https://example.com 😀")); // 成功
console.log(tweetSchema.safeParse("あ".repeat(150))); // エラー
5. Jest で TypeScript のテスト
Jest でのテストコード
import { countTwitterCharacters } from "../src/countTwitterCharacters";
test("valid tweet", () => {
expect(countTwitterCharacters("これはテストです!")).toBe(10);
});
test("tweet with URL", () => {
expect(countTwitterCharacters("https://example.com")).toBe(23);
});
test("tweet exceeds limit", () => {
expect(countTwitterCharacters("あ".repeat(150))).toBeGreaterThan(280);
});
まとめ
Twitter API の文字数カウントを PHP(Laravel)と TypeScript(Zod) で実装し、
✅ Laravel で独自バリデーションを作成
✅ PHPUnit でテストを実施
✅ TypeScript でリアルタイムチェック(Zod を使用)
✅ Jest で TypeScript のテストを実装
バリデーションが強化され、API リクエスト前にチェック可能 になりました。
この実装を活用して、確実に投稿できるシステムを構築しましょう!