0

0

文本分词与带引号短语保留的JavaScript实现

花韻仙語

花韻仙語

发布时间:2025-09-01 15:12:11

|

171人浏览过

|

来源于php中文网

原创

文本分词与带引号短语保留的javascript实现

本文详细介绍了如何在JavaScript中将文本字符串拆分为独立的词语,同时确保双引号内的短语作为一个整体被保留。通过采用有限状态机(FSM)的原理,我们能够健壮地处理各种复杂的输入情况,包括多余空格、引号内部的空格以及引号缺失等边缘情况,最终输出一个包含所有独立词语和完整短语的数组。

文本解析挑战:词语与短语的分离

在处理用户输入或文本数据时,我们经常需要将一个长字符串拆分成独立的“词语”或“标记”(tokens)。然而,简单的空格分割(例如 string.split(' '))往往不足以应对复杂场景,特别是当我们需要将双引号内的短语视为一个不可分割的整体时。例如,对于输入字符串 "on time" flight,我们期望得到的结果是 ["on time", "flight"],而不是 [""on", "time"", "flight"]。

传统的 split(' ') 方法会错误地将 "on time" 分割成 ""on 和 time"",这显然不符合我们的预期。为了解决这一问题,我们需要一种更智能的解析策略,能够识别并处理双引号的边界。

有限状态机(FSM)解析策略

处理这类字符串解析问题的强大工具是有限状态机(Finite-State Machine, FSM)。FSM通过定义一组“状态”和“状态转换规则”,来模拟解析过程。在我们的场景中,可以定义两种主要状态:

  1. word 状态:表示当前正在解析一个普通的词语(不在双引号内)。
  2. phrase 状态:表示当前正在解析一个双引号内的短语。

解析器会根据当前字符和当前状态,决定是继续累积当前词语/短语,还是切换到另一个状态,并完成当前词语/短语的收集。

立即学习Java免费学习笔记(深入)”;

FSM的实现细节

下面我们将通过一个JavaScript函数 splitToWordsWithQuotes 来实现这个FSM解析器:

Insou AI
Insou AI

Insou AI 是一款强大的人工智能助手,旨在帮助你轻松创建引人入胜的内容和令人印象深刻的演示。

下载
function splitToWordsWithQuotes(str) {
    let mode = null; // null: 初始状态/空白状态, 'word': 正在解析词语, 'phrase': 正在解析短语
    const words = []; // 存储解析出的词语和短语
    let currentToken = ''; // 临时存储当前正在构建的词语或短语

    // 辅助函数:完成当前词语/短语的收集,并重置 currentToken
    const completeToken = () => {
        if (currentToken.length > 0) { // 只有当 currentToken 非空时才添加
            words.push(currentToken);
            currentToken = '';
        }
    };

    for (let i = 0; i < str.length; i++) {
        const char = str[i];

        // 1. 初始状态或空白状态 (mode 为 null)
        if (mode === null) {
            if (char === ' ') {
                continue; // 跳过前导空格
            }
            if (char === '"') {
                mode = 'phrase'; // 遇到双引号,进入短语模式
            } else {
                currentToken += char;
                mode = 'word'; // 遇到非空格非引号字符,进入词语模式
            }
            continue;
        }

        // 2. 处理双引号字符
        if (char === '"') {
            completeToken(); // 遇到引号,意味着当前词语/短语结束
            // 切换模式:如果当前是词语模式,则下一个是短语;如果是短语模式,则下一个是词语。
            // 实际上,这里是结束当前短语模式,并准备进入下一个词语模式 (或等待下一个引号进入短语模式)
            // 修正:当遇到引号时,总是结束当前模式,并将模式设为 null,等待下一个字符决定新模式。
            // 更精确的做法是:如果当前是 phrase 模式,引号表示短语结束,回到 null 模式。
            // 如果当前是 word 模式,引号表示词语结束,进入 phrase 模式。
            // 考虑到FSM的简洁性,这里可以简化为:引号总是完成当前token,并切换模式。
            // 如果当前是 'word' 模式,遇到 '"',表示词语结束,进入 'phrase' 模式。
            // 如果当前是 'phrase' 模式,遇到 '"',表示短语结束,回到 'null' 模式(等待下一个token的开始)。
            mode = (mode === 'phrase') ? null : 'phrase';
            continue;
        }

        // 3. 处理空格字符
        if (char === ' ') {
            if (mode === 'phrase') {
                currentToken += ' '; // 在短语模式下,空格是短语内容的一部分
                continue;
            }
            // 在词语模式下,空格表示当前词语结束
            completeToken();
            mode = null; // 回到 null 模式,等待下一个词语或短语的开始
            continue;
        }

        // 4. 处理其他字符 (字母、数字等)
        currentToken += char; // 将字符添加到当前词语/短语中
        // 如果当前是 null 模式,且遇到非空格非引号字符,则进入 'word' 模式
        if (mode === null) {
            mode = 'word';
        }
    }

    // 循环结束后,确保最后一个词语/短语被收集
    completeToken();

    return words;
}

示例代码与运行效果

为了更好地理解上述FSM的工作原理,我们提供一些测试用例:

const myStr = '    "hello guys", some     words with "quotes inside" some spaces inside " please keep quoted words as one "phrase / word" end-of-line ';
const myWrongStr = '"hello guys", some words" with "quotes inside" please keep quoted words as one "phrase / word" '; // 包含未闭合引号的示例

console.log('--- 正常输入示例 ---');
console.log('输入:', myStr);
console.log('输出:', splitToWordsWithQuotes(myStr));
// 预期输出: ["hello guys", "some", "words", "with", "quotes inside", "some", "spaces", "inside", "please", "keep", "quoted words as one", "phrase / word", "end-of-line"]

console.log('
--- 包含未闭合引号的示例 ---');
console.log('输入:', myWrongStr);
console.log('输出:', splitToWordsWithQuotes(myWrongStr));
// 预期输出: ["hello guys", "some", "words" with "quotes inside", "please", "keep", "quoted words as one", "phrase / word"]
// 注意:对于未闭合的引号,FSM会将其视为普通字符,或将后续内容都视为短语的一部分,直到遇到下一个引号或字符串结束。

console.log('
--- 原始问题示例 ---');
const originalInput = '"on time" "flight"';
console.log('输入:', originalInput);
console.log('输出:', splitToWordsWithQuotes(originalInput));
// 预期输出: ["on time", "flight"]

代码解析:

  • mode 变量:是FSM的核心,它跟踪当前解析器所处的状态。
    • null:表示当前不在解析任何词语或短语,可能处于多个词语/短语之间的空白区域。
    • 'word':表示正在收集一个普通词语。
    • 'phrase':表示正在收集一个双引号内的短语。
  • words 数组:用于存储最终解析出的所有词语和短语。
  • currentToken 变量:一个字符串缓冲区,用于累积当前正在解析的词语或短语的字符。
  • completeToken() 辅助函数:当一个词语或短语完成时(例如遇到空格或引号),此函数将 currentToken 添加到 words 数组中,并清空 currentToken 以便开始收集下一个。
  • 循环遍历字符:代码逐个字符地检查输入字符串。
  • 状态转换逻辑
    • 遇到空格
      • 如果在 'phrase' 模式下,空格被视为短语的一部分,直接添加到 currentToken。
      • 如果在 'word' 模式下,空格表示当前词语结束,调用 completeToken() 并将 mode 重置为 null。
    • 遇到双引号 "
      • 无论当前处于何种模式,双引号都意味着当前 currentToken 的结束。调用 completeToken()。
      • 然后,如果之前是 'phrase' 模式,则双引号表示短语结束,mode 切换回 null(等待下一个词语/短语)。
      • 如果之前是 null 或 'word' 模式,双引号表示开始一个新短语,mode 切换到 'phrase'。
    • 遇到其他字符
      • 这些字符总是添加到 currentToken。
      • 如果 mode 是 null,则表示开始了一个新词语,将 mode 设置为 'word'。
  • 循环结束后的处理:在 for 循环结束后,需要再次调用 completeToken(),以确保字符串末尾的任何未完成的词语或短语被正确收集。

注意事项与扩展

  1. 未闭合的引号:当前的FSM实现对于未闭合的引号,会将后续内容都视为短语的一部分,直到字符串结束或遇到下一个引号。如果需要更严格的错误处理(例如抛出错误或记录警告),可以在 phrase 模式下,在循环结束后检查 mode 是否仍为 'phrase'。
  2. 转义引号:如果短语内部可能包含转义的双引号(例如 "),当前的FSM不会将其视为普通字符,而是会错误地将其解释为短语的结束。处理这种情况需要更复杂的FSM逻辑,例如引入一个“转义字符”状态。
  3. 性能:对于非常长的字符串,逐字符遍历的FSM通常比正则表达式具有更好的性能和可读性,尤其是在处理复杂嵌套或状态依赖的解析任务时。
  4. 后处理:本教程的FSM旨在将字符串解析成一个词语/短语数组。如果需要将此数组进一步格式化成特定的字符串(例如,将短语用 " 包裹并连接),则需要额外的后处理步骤。例如,如果需要将 ["on time", "flight"] 转换为 ""on time"flight",可以这样做:
    const tokens = splitToWordsWithQuotes('"on time" "flight"');
    const formattedOutput = tokens.map(token => {
        // 如果token包含空格,通常意味着它是一个短语,用双引号包裹
        if (token.includes(' ')) {
            return `"${token}"`; // 或者 `\"${token}\"` 如果需要字面量反斜杠
        }
        return token;
    }).join('');
    console.log('格式化后的输出:', formattedOutput); // 示例输出: "on time"flight

    请注意,原始问题中期望的 ""ON TIME"FLIGHT" 格式可能包含额外的转义或特定含义,需要根据具体需求调整后处理逻辑。

总结

通过采用有限状态机(FSM)的方法,我们能够健壮且高效地将复杂的文本字符串拆分为独立的词语和带引号的短语。这种方法不仅解决了简单 split() 函数的局限性,还为处理更复杂的文本解析任务提供了可扩展的基础。理解FSM的原理并将其应用于字符串处理,是提升JavaScript编程技能的重要一步。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

531

2023.06.20

正则表达式不包含
正则表达式不包含

正则表达式,又称规则表达式,,是一种文本模式,包括普通字符和特殊字符,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。php中文网给大家带来了有关正则表达式的相关教程以及文章,希望对大家能有所帮助。

258

2023.07.05

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

766

2023.07.05

java正则表达式匹配字符串
java正则表达式匹配字符串

在Java中,我们可以使用正则表达式来匹配字符串。本专题为大家带来java正则表达式匹配字符串的相关内容,帮助大家解决问题。

219

2023.08.11

正则表达式空格
正则表达式空格

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。本专题为大家提供正则表达式相关的文章、下载、课程内容,供大家免费下载体验。

357

2023.08.31

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

293

2023.11.13

正则表达式空格如何表示
正则表达式空格如何表示

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。想了解更多正则表达式空格怎么表示的内容,可以访问下面的文章。

245

2023.11.17

正则表达式中如何匹配数字
正则表达式中如何匹配数字

正则表达式中可以通过匹配单个数字、匹配多个数字、匹配固定长度的数字、匹配整数和小数、匹配负数和匹配科学计数法表示的数字的方法匹配数字。更多关于正则表达式的相关知识详情请看本专题下面的文章。php中文网欢迎大家前来学习。

548

2023.12.06

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号