Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

OSSコミットしてZennの課題を解決した話

 OSSコミットしてZennの課題を解決した話

dyoshikawa

July 21, 2024
Tweet

More Decks by dyoshikawa

Other Decks in Technology

Transcript

  1. 使い方の例 import ogs from "open-graph-scraper"; (async () => { const

    data = await ogs({ url: "https://classmethod.jp/", }); console.log(JSON.stringify(data.result, null, 2)); })(); OGの読み取りにopen-graph-scraperを使用
  2. クラスメソッドコーポレートサイトを読み取るとこんな感じ https://classmethod.jp/ { "success": true, "ogLocale": "ja_JP", "ogSiteName": "クラスメソッド株式会社", "ogType":

    "article", "ogTitle": "クラスメソッド株式会社", "ogDescription": "クラスメソッドはクラウド、デジタル化、データの3つの分野を掛けあわせて、お客様のビジネス成長に向けた技術支援を行います。2022年に "以下省略": "..." } OGの読み取りにopen-graph-scraperを使用
  3. 阿部寛のホームページを読み取った場合 import ogs from "open-graph-scraper"; // v6.3.4 (async () =>

    { const { result } = await ogs({ url: 'http://abehiroshi.la.coocan.jp/' }) console.log(JSON.stringify(result, null, 2)) })(); 以下の結果に { "ogTitle": "�������̃z�[���y�[�W", // "阿部寛のホームページ"を期待 "charset": "Shift_JIS", "requestUrl": "http://abehiroshi.la.coocan.jp/", "success": true } 課題: open-graph-scraperをアップデートできない
  4. そういう場合はREPLACEMENT CHARACTER( � )の出番になる 実際手元で試すと 阿部 は ���� になった 88a29594

    は4バイトなので、1バイト区切りで ���� になったと思 われる(デコーダの実装によりそう) ➡️ 例2: Shift_JISの文字列をUTF-8でデコードする場合 阿 88a2 部 9594 Shift_JIS � efbfbd � efbfbd � efbfbd � efbfbd UTF-8
  5. UTF-8での cc83 Unicodeでは U+0303 のチルダ ~ はCOMBINED TILDEといって、他の文字と組み合わせて使うものらしい REPLACEMENT CHARACTER

    � と組み合わさって �̃ になる 発音表記などで使われる ちなみに: 文字化けに � でない文字がある件
  6. fetch() + text() の時点でUTF-8デコーディングが行われる response = await fetch(/* 省略 */);

    body = await response.text(); text() の時点で文字化けが発生してしまうため、ここに手を入れ る必要がある text() は Response インターフェイスのメソッドで、 Response ストリームを取得して完全に読み込みます。 String で解決する プロミスを返します。 レスポンスは常に UTF-8 としてデコードされます。 https://developer.mozilla.org/ja/docs/Web/API/Response/text どんなPRを出したの?元コードの挙動
  7. 一応、ミニマムなコードで動作を確認してみる (async () => { const response = await fetch("http://abehiroshi.la.coocan.jp/");

    const body = await response.text(); // 243文字目が<title />の中身の `�` にあたる console.log(body[243], dummy.charCodeAt(243).toString(16)); // � fffd })(); dummy.charCodeAt(243) の結果(Code Unit)が fffd であり、こ れはUTF-16における � のバイト列である Node.jsは内部的にUTF-16を採用している つまり、やはり元のバイト列は残っておらず復元は困難である どんなPRを出したの?元コードの挙動
  8. text() ではなく arrayBuffer() を使うことでデコード前のバイト 列を取得し、 bodyArrayBuffer 変数で保持しておく bodyArrayBuffer を保持したままUTF-8デコードを行い、 <meta

    charset="{charset}" /> を取得するなどして文字コードを特定する 特定した文字コードで bodyArrayBuffer をデコードする const bodyArrayBuffer = await response.arrayBuffer(); const bodyText = Buffer.from(bodyArrayBuffer).toString('utf-8'); const charset = getCharset(bodyText, bodyArrayBuffer, load(bodyText)); if (charset.toLowerCase() === 'utf-8') { body = bodyText; } else { body = decode(Buffer.from(bodyArrayBuffer), charset); } どんなPRを出したの?こう変更した
  9. 特殊用途文字 (Unicodeのブロック) - Wikipedia とほほの文字コード入門 - とほほのWWW入門 UTF-8 - Wikipedia

    JIS X 0208コード表 - CyberLibrarian 文字列とUnicode · JavaScript Primer #jsprimer JavaScript における文字コードの初歩 - 30歳からのプログラミング (プログラマのための)いまさら聞けない標準規格の話 第2回 文字コー ド実践編 | オブジェクトの広場 参考