Xiao Han, CEO da Jina, compartilhou um trecho de código impressionante no GitHub da implementação central de fragmentação usada no tokenizador da Jina. O trecho de código da expressão regular tem pouco mais de 50 linhas e, ainda assim, lida com eficiência com o conteúdo de texto de todas as complexidades. O desempenho é surpreendentemente robusto.
// Atualizado: 15 de agosto de 2024 // Executar: node testRegex.js testText.txt // Usado em https://jina.ai/tokenizer const fs = require('fs'); const util = require('util'); // Definir variáveis para números mágicos const MAX_HEADING_LENGTH = 7; const MAX_HEADING_CONTENT_LENGTH = 7; // Define variáveis para números mágicos. const MAX_HEADING_CONTENT_LENGTH = 200; const MAX_HEADING_CONTENT_LENGTH = 1; // Define variáveis para números mágicos. 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_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_TABLE_LENGTH = 2000; const const MIN_HORIZONTAL_RULE_LENGTH = 3; const MAX_SENTENCE_LENGTH = 3; e 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; // Número de caracteres para procurar um limite de frase à frente // Definir o padrão regex // Títulos // Títulos // Itens de lista // Citações em bloco // Blocos de código // Tabelas // Regras horizontais // Linhas ou frases autônomas // Sentenças ou frases // Texto citado, frases parentéticas ou conteúdo entre colchetes // Parágrafos // Tags do tipo HTML e seu conteúdo // Expressões matemáticas no estilo LaTeX // Fallback para qualquer conteúdo restante // Ler o regex e testar o texto dos arquivos const chunkRegex = new RegExp( "(" + // 1. títulos (estilo Setext, Markdown e HTML, com restrições de comprimento) `(? :^(? :[#*=-]{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]>)? (? :\\r?\\\\n|$))` + "|" + // Novo padrão para citações `(? :\\\[[0-9]+\\\\][^\\\r\\\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}})` + "|" + // 2. itens de lista (listas com marcadores, numeradas, com letras ou de tarefas, inclusive aninhadas, até três níveis, com restrições de comprimento) `(? :(? :^|\\\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}])(? =\\\\s|$))|(? :\\\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}])(? =\\\s|$))?))) ` + `(? :(? :\\\\r?\\\\n[ \\\\t]{2,5}(? :[-*+-]|\\\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}])(? =\\\\s|$))|(? :\\\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}])(? =\\\s|$))?)))))) ` + `{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}])(? =\\\\s|$))|(? :\\\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}])(? =\\\s|$))?)))))) ` + `{0,${MAX_NESTED_LIST_ITEMS}}))?) ` + "`|" + // 3. citações em bloco (incluindo citações aninhadas e citações, até três níveis, com restrições de comprimento) Citações em bloco (incluindo citações aninhadas e citações, até três níveis, com restrições de comprimento) :(? :^>(? :>|\\\s{2,}){0,2}(? A seguir, uma lista dos três níveis até três com restrições de comprimento :\\b[^\\\r\\n]{0,${MAX_BLOCKQUOTE_LINE_LENGTH}}\b(? :[.!? ...]|\\\\... {3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(? =\\\s|$))|(? :\\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}])(? =\\\s|$))?)))) \\\r?\\\n?){1,${MAX_BLOCKQUOTE_LINES}})` + "|" + // Blocos de código (cercados, recuados ou tags HTML pré/código, com restrições de comprimento) Blocos de código (com cercas, recuos ou tags HTML pré/código, com restrições de comprimento) `(? :(? :^|\\\r?\\n)(? :\`\`\\`|~~~~)(? :\\\w{0,${MAX_CODE_LANGUAGE_LENGTH}})? \\\r?\\\\n[\\\s\\\S]{0,${MAX_CODE_BLOCK_LENGTH}}? (? :\`\`\`|~~~)\\\r?\\\\n?\+ `|(? :(? :^||\\\r?\\\\n)(? : {4}|\\\t)[^\\\r\\\\n]{0,${MAX_LIST_ITEM_LENGTH}}(? :\\r?\\\\n(? : {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>))` + "|" + // Tabelas (Markdown, tabelas de grade e tabelas HTML, com restrições de comprimento) Tabelas (Markdown, tabelas de grade e tabelas HTML, com restrições de comprimento) :(? :^|\\\\r?\\\n)(? :\\\|[^\\\\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>))` + "|" + // Regras horizontais (tags hr de Markdown e HTML) `(? :^(? :[-*_]){${MIN_HORIZONTAL_RULE_LENGTH},}\\s*$|<hr\\s*/?>)` + "|" + // Linhas ou frases autônomas (incluindo blocos de linha única e elementos HTML, com restrições de comprimento) `(? :^(? : : : + "|" + // 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}])(? =\\\s|$))|(? :[^\\\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}])(? =\\\s|$))?)))) (? :</[a-zA-Z]+>)? (? :\\r?\\\\n|$))` + "|" + // Sentenças ou frases que terminam com pontuação (incluindo reticências e pontuação Unicode) Sentenças ou frases que terminam com pontuação (incluindo reticências e pontuação Unicode) Sentenças ou frases que terminam com pontuação (incluindo reticências e pontuação Unicode) `(? :[^\\r\\n]{1,${MAX_SENTENCE_LENGTH}}(? :[.!? ...]|\\\\... \\\\...\...\...\...\. \\\...\...\...\...\... |[\\u2026\\\\u2047-\u2049]|[\\p{Emoji_Presentation}\\\p{Extended_Pictographic}])(? =\\\s|$))|(? :[^\\\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}])(? =\\\\s|$))?))) ` + "|" + // Texto entre aspas, frases parentéticas ou conteúdo entre colchetes (com restrições de comprimento) "(? :" + `(?<!\\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}])(? =\\\s|$))|(? :[^\\\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}])(? =\\\s|$))?)))) (? :</p>)? (? =\\\r?\\\\n\\\\r?\\n|$))` + "|" + // Tags do tipo HTML e seu conteúdo (incluindo tags e atributos de fechamento automático, com restrições de comprimento) `(? :: A seguir, um resumo das tags semelhantes a HTML e seu conteúdo (incluindo tags e atributos de fechamento automático, com restrições de comprimento)<[a-zA-Z][^>]{0,${MAX_HTML_TAG_ATTRIBUTES_LENGTH}}(? :>[\\s\\S]{0,${MAX_HTML_TAG_CONTENT_LENGTH}}?</[a-zA-Z]+>|\\s*/>))` + "|" + // 12. expressões matemáticas no estilo LaTeX (em linha e em bloco, com restrições de comprimento) `(? :(? :\\\$\\$[\\s\\S]{0,${MAX_MATH_BLOCK_LENGTH}}? \\\\$\\$)\(? :\\\$[^\\$\\r\\n]{0,${MAX_MATH_INLINE_LENGTH}}\\\$))` + "|" + // 14. fallback para qualquer conteúdo restante (com restrições de comprimento) `(? :(? :[^\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}}(? :[.!? ...]|\\\\... {3}|[\\u2026\u2047-\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}])(? =\\\s|$))|(? :[^\\\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}])(? =\\\s|$))?))) ` + ")", "gmu" ); // ler do arquivo arg[1] const testText = fs.readFileSync(process.argv[2], 'utf8'); // Função para formatar bytes em uma string legível por humanos function formatBytes(bytes) { if (bytes < 1024) return bytes + " bytes"; Caso contrário, se (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB"; Caso contrário, se (bytes { console.log(util.inspect(match, {maxStringLength: 50})); { }); } else { console.log('Nenhum pedaço encontrado.'); }); } else { console.log(util.inspect(match({maxStringLength: 50})) } // Sinalizadores de regex de saída console.log(`\nSinalizadores de regex: ${chunkRegex.flags}`); // Sinalizadores de regex de saída. // Verificação de possíveis problemas Se (executionTime > 5) { console.warn('\nAviso: o tempo de execução excedeu 5 segundos. A regex pode ser muito complexa ou a entrada muito grande.'); } } if (memoryUsed > 100 * 1024 * 1024) { console.warn('\nWarning: o uso de memória excedeu 100 MB. Considere processar a entrada em partes menores.'); } if (memoryUsed > 100 * 1024 * 1024) { console.warn('\nWarning: o uso de memória excedeu 100 MB. }
As expressões regulares nesse código levam em conta uma variedade de estruturas de texto, incluindo cabeçalhos, itens de lista, referências de bloco, blocos de código, tabelas, regras horizontais, linhas ou frases separadas, sentenças ou frases com pontuação, texto entre aspas, conteúdo de parênteses, blocos de código, tabelas, regras horizontais, linhas ou frases separadas, conteúdo de tags HTML, expressões matemáticas LaTeX e muito mais. Ele se aproxima da fragmentação do texto por meio de padrões cuidadosamente projetados, embora as expressões regulares em si não entendam o contexto ou a semântica do texto.
A expressão regular no exemplo de código usa "backtracking", o que é essencial para uma segmentação semântica mais significativa. Por exemplo, ela não é interrompida no meio de uma frase. Entretanto, para listas profundamente aninhadas, referências de bloco ou estruturas como parênteses, o retrocesso pode ser difícil. Para otimizar esses casos, as expressões regulares podem ser aprimoradas para lidar melhor com vários níveis de aninhamento e limitar o aninhamento a níveis práticos, como até 3 níveis, para garantir o desempenho e evitar retrocessos catastróficos.
Embora esse código possa não estar muito completo, mas de acordo com essa ideia de otimizar os detalhes, podemos prever que o efeito pode ser aprimorado ainda mais. Os serviços oficiais de nuvem da Jina fornecidos pela interface oficial do particípio para que os desenvolvedores experimentem o uso e são gratuitos.
versão do python