JinaのCEOであるシャオ・ハンが、Jinaトークナイザーで使われているチャンキングのコア実装の印象的なコード・スニペットをGitHubで共有した。正規表現のコードスニペットは50行強の長さだが、あらゆる複雑なテキストコンテンツのチャンキングを効率的に処理している。性能は驚くほど堅牢だ。
// 更新日:2024年8月15日 // 実行: node testRegex.js testText.txt // https://jina.ai/tokenizer で使用 const fs = require('fs'); const util = require('util'); // マジックナンバー用の変数を定義 const MAX_HEADING_LENGTH = 7; const MAX_HEADING_CONTENT_LENGTH = 7; // マジックナンバー用の変数を定義する。 const MAX_HEADING_CONTENT_LENGTH = 200; const MAX_HEADING_CONTENT_LENGTH = 1; // マジックナンバー用の変数を定義します。 const MAX_HEADING_CONTENT_LENGTH = 200; const MAX_HEADING_UNDERLINE_LENGTH = 200; const MAX_HTML_HEADING_LENGTH = 7。 const MAX_HEADING_CONTENT_LENGTH = 200; const MAX_HEADING_UNDERLINE_LENGTH = 200; const MAX_HTML_HEADING_ATTRIBUTES_LENGTH = 100; const MAX_LIST_ITEM_LENGTH = 200; const MAX_NESTED_LIST_ITEMS = 6; const MAX_LIST_INDENT_SPACES = 7; const MAX_BLOCKQUOTE = 7; const MAX_LIST_INDENT_SPACES = 8 const MAX_BLOCKQUOTE_LINE_LENGTH = 200; const MAX_BLOCKQUOTE_LINE_LENGTH = 200; const MAX_BLOCKQUOTE_LINES = 15; const MAX_CODE_BLOCK_LENGTH = 1500; const MAX_CODE_LANGUAGE_LENGTH = 20; const MAX_INDENTED_CODE_LINES = 20; const MAX_TABLE_CELL_LENGTH = 200; const MAX_TABLE_ROWS = 20; const MAX_HTML_TABLE_ROWS = 20; const MAX_HTML_ROWS = 20 const MAX_HTML_TABLE_LENGTH = 2000; const const MIN_HORIZONTAL_RULE_LENGTH = 3; const MAX_SENTENCE_LENGTH = 3; および const MAX_SENTENCE_LENGTH = 400; const MAX_QUOTED_TABLE_LENGTH = 20; const const MAX_QUOTED_TEXT_LENGTH = 300; const const MAX_PARENTHETICAL_CONTENT_LENGTH = 200; const MAX_NESTED_PARENTHESES = 5; const MAX_MATH_BLOCK_LENGTH = 500; const MAX_PARAGRAPH_PARENTHESES = 5 const MAX_PARAGRAPH_LENGTH = 1000; const MAX_STANDALONE_LINE_LENGTH = 800; const MAX_HTML_TAG_ATTRIBUTES_LENGTH = 100; const MAX_HTML_TAG_ATTRIBUTES_LENGTH = 100; const MAX_HTML_TAG_LENGTH = 100 const MAX_HTML_TAG_CONTENT_LENGTH = 1000; const LOOKAHEAD_LENGTH = 100; const const LOOKAHEAD_RANGE = 100; // 文の境界を先読みする文字数 // 正規表現パターンの定義 // 見出し // 見出し // リスト項目 // ブロック引用符 // コードブロック // テーブル // 水平ルール // 独立した行またはフレーズ // センテンスまたはフレーズ // 引用テキスト、括弧付きフレーズ、または括弧付きコンテンツ // 段落 // HTMLライクなタグとその内容 // LaTeXスタイルの数式 // 残りのコンテンツに対するフォールバック // 正規表現とテストテキストをファイルから読み込む const chunkRegex = new RegExp( "(" + // 1. 見出し(Setextスタイル、Markdownスタイル、HTMLスタイル、長さの制約あり) `(?:^(?:[#*=-]{1,${MAX_HEADING_LENGTH}}|\\w[^\\r\\\n]{0,${MAX_HEADING_CONTENT_LENGTH}}\\\r?\\n[-=]{2,${MAX_HEADING_underline_length}}<h[1-6][^>]{0,${MAX_HTML_HEADING_ATTRIBUTES_LENGTH}}>)[^\\r\\n]{1,${MAX_HEADING_CONTENT_LENGTH}}(?:</h[1-6]>)?(?))` +. "|" + // 引用のための新しいパターン `(?:\\\[[0-9]+\\\\][^\\\r\\\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}})` + "|" + // リスト項目(箇条書き、番号付き、文字付き、またはタスクリスト。) `(?:(?:^|\\\r?\\n)[\\\t]{0,3}(?:[-*+-]|\\d{1,3}\\\\.\\\w\\\\.|\\\\\((xX)┛)[ ┛t]+(?(xX]㎟)[㎟t]+(?:\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?:[.!?...]|\\\\.{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?=[\\\r\\n]|$))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\\b(?=[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))))?` + `(?:(?ʕ-̫͡-ʔ-̫͡-ʔ-̫͡-ʔ(?:[-*+-]|\\\d{1,3}\\\...\\\w\\\\.|\\\\\((xX)┛)[ (xX)┛)[ (xX)┛)[ (xX)┛) +(?(xX)㎟)[㎟t]+(?:\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?:[.!?...]|\\\\.{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?=[\\\r\\n]|$))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\\b(?=[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\)))))?` + `{0,${max_nested_list_items}}(?:\\r?\\\n[ \\\t]{4,${MAX_LIST_INDENT_SPACES}}}(?:[-*+-]|\\\d{1,3}\\\...\\\w\\\.|\\\\¦[[ xX]¦])[ ¦t]+(?(xX)㎟㎟)[㎟㎟t]+(?:\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?:[.!?...]|\\\\.{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\b(?=[\\\r\\n]|$))|(?:\\\b[^\\\r\\n]{1,${MAX_LIST_ITEM_LENGTH}}\\b(?=[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\)))))?` + `{0,${max_nested_list_items}})))?` + "`|" + // 3.ブロック引用(入れ子になった引用と引用を含む、3レベルまで、長さ制限あり) ブロック引用(入れ子になった引用と引用を含む。):(?:^>(?:>|\\\s{2,}){0,2}(?長さ制約付きで3レベルまでとする。:\\b[^\\\r\\n]{0,${MAX_BLOCKQUOTE_LINE_LENGTH}}\b(?:[.!?...]|\\\\...{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:\\\b[^\\\r\\n]{0,${MAX_BLOCKQUOTE_LINE_LENGTH}}\\b(?=[\\\r\\n]|$))|(?:\\\b[^\\\r\\n]{0,${MAX_BLOCKQUOTE_LINE_LENGTH}}\\b(?=[.!?...]|\\\\.{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}]])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))))?\\\r?\\\n?){1,${MAX_BLOCKQUOTE_LINES}})` + "|" + // コードブロック(フェンス付き、インデント付き、またはHTMLのpre/codeタグ。) コードブロック(フェンス、インデント、またはHTMLのpre/codeタグ。:(?:^|r?\n)(?:\`\`\\`|~~~~)(?:\\\w{0,${MAX_CODE_LANGUAGE_LENGTH}})?\\\r?\\\\n[\\\s\\\S]{0,${MAX_CODE_BLOCK_LENGTH}}?(?:\`\`\`|~~~)\\\r?\\\\n?\+ `|(?:(?:^||ヽ)(?: {4}|\\\t)[^\\\r\\\\n]{0,${MAX_LIST_ITEM_LENGTH}}(?ʬʬʬʬʬʬ: {4}|\\\t)[^\\\r\\\\n]{0,${MAX_LIST_ITEM_LENGTH}}){0,${MAX_INDENTED_CODE_LINES}}}\\r\\\\n?)` + `|(?:<pre>(?:<code>)?[\\s\\\S]{0,${MAX_CODE_BLOCK_LENGTH}}?(?:</code>)?</pre>))` + "|" + // テーブル(Markdown、グリッドテーブル、HTMLテーブル。) テーブル(Markdown、グリッドテーブル、HTMLテーブル、長さ制限あり):(?(長さ制約あり) :(?:\\\|[^\\\\r\\\n]{0,${MAX_TABLE_CELL_LENGTH}}\\|(?:\\\r?\\\n\\\\|[-:]{1,${MAX_TABLE_CELL_LENGTH}}\\|){0,1}(?:\\\r?\\\n\\\\|[^\\\r\\n]{0,${MAX_TABLE_CELL_LENGTH}}\\|){0,${MAX_TABLE_ROWS}}` + `|<table>[\\s\\\S]{0,${MAX_HTML_TABLE_LENGTH}}?</table>))` + "|" + // 6.水平方向のルール(MarkdownとHTMLのhrタグ) `(?:^(?:[-*_]){${MIN_HORIZONTAL_RULE_LENGTH},}\\s*$|<hr\\s*/?>)` + "|" + // 10.独立した行またはフレーズ (単一行ブロックおよび HTML 要素を含み、長さの制約がある) `(?:^(?: : : + "|" + // 10.<[a-zA-Z][^>]{0,${max_html_tag_attributes_length}})?(?:(?:[^\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?:[.!?...]|\\\\\.\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))|(?:[^\\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?=[\\\r\\\\n]|$))|(?:[^\\\r\\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?=[.!?...]|\\\\...\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))))?(?:</[a-zA-Z]+>)?(?))` +. "|" + // 句読点で終わる文または語句 (省略記号および Unicode 句読点を含む) 句読点で終わる文または語句(省略記号および Unicode の句読点を含む)句読点(省略記号および Unicode 句読点を含む)で終わる文または句 `(?:[^\\r\\n]{1,${MAX_SENTENCE_LENGTH}}(?:[.!?...]|\\\\...\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))|(?:[^\\\r\\n]{1,${MAX_SENTENCE_LENGTH}}(?=[\\r\\\n]|$))|(?:[^\\\r\\\n]{1,${MAX_SENTENCE_LENGTH}}(?=[.!?...]|\\\\.\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...\\\\...\...\...\...\.\\\...\...\...\...\...|[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))))?` + "|" + // 引用テキスト、括弧付きフレーズ、または括弧付きコンテンツ(長さ制限あり) "(?:" + `(?<!\\w)\"\"\"[^\"]{0,${MAX_QUOTED_TEXT_LENGTH}}\"\"\"(?!\\w)` + `|(?<!\\w)(?:['\"\`'"])[^\\r\\n]{0,${MAX_QUOTED_TEXT_LENGTH}}\\1(?!\\w)` + `|\\([^\\r\\n()]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}(?:\\([^\\r\\n()]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}\\)[^\\r\\n()]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}){0,${MAX_NESTED_PARENTHESES}}\\)` + `|\\[[^\\r\\n\\[\\]]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}(?:\\[[^\\r\\n\\[\\]]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}\\][^\\r\\n\\[\\]]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}){0,${MAX_NESTED_PARENTHESES}}\\]` + `|\\$[^\\r\\n$]{0,${MAX_MATH_INLINE_LENGTH}}\\$` + `|\`[^\`\\r\\n]{0,${MAX_MATH_INLINE_LENGTH}}\`` + ")" + "|" + // 9. Paragraphs (with length constraints) `(?:(?:^|\\r?\\n\\r?\\n)(?:<p>)?(?:(?:[^\\r\\n]{1,${MAX_PARAGRAPH_LENGTH}}(?:[.!?...]|\\\\...{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:[^\\\r\\n]{1,${MAX_PARAGRAPH_LENGTH}}(?=[\\\r\\\\n]|$))|(?:[^\\\r\\\n]{1,${MAX_PARAGRAPH_LENGTH}}(?=[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))))?(?:</p>)?(?=\\\))` +. "|" + // HTMLライクなタグとその内容(自己閉じタグと属性を含む。) `(?:: 以下はHTMLライクなタグとその内容(自己閉じタグと属性を含む、長さの制約あり)の要約である。<[a-zA-Z][^>]{0,${max_html_tag_attributes_length}}(?:>[\\s\\S]{0,${MAX_HTML_TAG_CONTENT_LENGTH}}?</[a-zA-Z]+>|\\s*/>))` + "|" + // 12. LaTeXスタイルの数式(インラインおよびブロック、長さ制限あり) `(?:(?:\\\$\\$[\\s\\S]{0,${MAX_MATH_BLOCK_LENGTH}}?\\\\(?)・・・・・・。:\\\$[^\\$\\r\\n]{0,${MAX_MATH_INLINE_LENGTH}}\\\$))` + "|" + // 14.残りのコンテンツに対するフォールバック(長さの制約あり) `(?:(?:[^\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?:[.!?...]|\\\\...{3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?=\\\))|(?:[^\\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?=[\\\r\\\\n]|$))|(?:[^\\\r\\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(?=[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(?:.{1,${lookahead_range}}(?:[.!?...]|\\\\...{3}|[\\\u2026\u2047-\u2049]|[\\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(?=\\\))))?` + ")", "gmu" ); // arg[1]ファイルから読み込む const testText = fs.readFileSync(process.argv[2], 'utf8'); // バイトを人間が読める文字列にフォーマットする関数 function formatBytes(bytes) { // バイトを人間が読める文字列にフォーマットする関数 if (bytes < 1024) return bytes + " bytes"; else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB"; else if (bytes マッチ, インデックス) { console.log(util.inspect(match, {maxStringLength: 50})); {。 }); } else { console.log('No chunks found.'); }); } else { console.log(util.inspect(match({maxStringLength: 50})). } // 正規表現フラグを出力する console.log(`nRegex flags: ${chunkRegex.flags}`); // 正規表現フラグを出力する。 // 潜在的な問題をチェックする if (executionTime > 5) { // 正規表現フラグを出力する。 console.warn(' \nWarning: 実行時間が5秒を超えました。 正規表現が複雑すぎるか、入力が大きすぎる可能性があります。'); }. } if (memoryUsed > 100 * 1024 * 1024) { { }. console.warn(' \nWarning: Memory usage exceeded 100 MB. Consider the processing the input in smaller chunks.'); } if (memoryUsed > 100 * 1024 * 1024) { console.warn(' \nWarning: Memory usage exceeded 100 MB. }
このコードの正規表現は、見出し、リストアイテム、ブロック参照、コードブロック、テーブル、水平ルール、独立した行やフレーズ、句読点を含む文やフレーズ、引用テキスト、括弧コンテンツ、コードブロック、テーブル、水平ルール、独立した行やフレーズ、HTMLタグコンテンツ、LaTeX数式など、さまざまなテキスト構造を考慮します。正規表現自体はテキストの文脈や意味を理解しませんが、注意深く設計されたパターンによってテキストのチャンキングを近似します。
コード例の正規表現では「バックトラック」を使用しているが、これはより意味のある意味でのセグメンテーションに不可欠である。例えば、文の途中で区切られることはない。しかし、深く入れ子になったリストやブロック参照、あるいは括弧のような構造では、バックトラックが困難になることがある。このようなケースを最適化するために、正規表現をさらに改良して、複数のレベルの入れ子をよりうまく扱えるようにし、入れ子を実用的なレベル、たとえば3レベルまでに制限することで、パフォーマンスを確保し、致命的なバックトラックを回避することができる。
このコードは非常に完全ではないかもしれないが、細部を最適化するために、この考えに従って、我々は効果がさらに改善の余地があることを予見することができます。ジーナ公式クラウドサービスは、開発者が使用することを経験するために分詞インターフェイスによって提供され、無料です。
パイソンバージョン