# 锐鸥RyO **Repository Path**: rybby/ryo ## Basic Information - **Project Name**: 锐鸥RyO - **Description**: 锐鸥是一款免费开源的网页框架,由锐白个人开发,通过该程序用户可以快速创建网页应用。锐鸥追求的是轻巧的编程体验,让程序开发像鸥鸟般轻盈快活。使用方法:请将锐鸥(Ryo)的源码文件(如:ryo_v2025.8.1.0.js)下载放到目标网站的 js 目录,然后在 html 页面加载,在 body 标签后进行初始化即可,锐鸥(Ryo)的初始化函数会在当前的 html 页面创建应用窗口界面。 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-31 - **Last Updated**: 2026-03-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 锐鸥(ryo):新一代模块化网站应用生态平台 在当今内容创作与数字服务日益多元化的互联网环境中,如何快速搭建功能丰富、可扩展且具备商业变现能力的网站平台,成为众多站长、博主和内容创作者的核心诉求。锐鸥(ryo) 正是为解决这一痛点而生——它不仅是一款网站应用工具,更是一个集内容发布、用户互动、商业运营与多方分润于一体的模块化生态系统。 ## 一、架构清晰:服务端 + 代理端协同运作 锐鸥采用双端架构设计: - **服务端(发行商端)**:由锐鸥官方(发行商)掌控,负责处理所有用户核心数据,包括注册、登录、支付、增值服务开通等敏感操作。服务端确保系统安全、数据统一与商业规则执行。 - **代理端(运营商端)**:面向站长或平台运营者开放,为共享软件形式。运营商可免费下载并使用基础功能,但若需启用高级特性或特定扩展应用/工具,则需向服务端付费解锁。 这种分离式架构既保障了核心数据的安全性,又赋予运营商高度的定制自由度,形成“轻部署、重运营”的灵活模式。 任何个人或企业都可以通过锐鸥(ryo)运营自己的内容平台,无需具备代码编程相关的知识,只需买一台服务器启动程序,选择开放相应的应用与工具供平台用户使用就可以坐享收益。 - **如何通过锐鸥(ryo)运营自己的内容平台**: 1. 安装锐派: pip install rypi 2. 安装锐网服务器管理工具: rypi ryweb install -p /data/ryweb 在使用锐网(ryweb)前,请先获得一台服务器,推荐使用以下服务商提供的云服务器:[雨云](https://www.rainyun.com/OTgwNjE2_),[阿里云](https://www.aliyun.com/minisite/goods?userCode=atermp2c),[腾讯云](https://curl.qcloud.com/mcypLU19),[西部数码](https://www.west.cn/active/freetc/?ReferenceID=490871)。 ## 二、模块化扩展:扩展应用 + 扩展工具,按需组合 锐鸥的核心优势在于其模块化扩展体系,由“扩展应用”与“扩展工具”两大部分构成,运营商可根据自身平台定位选择所需模块。 ### 扩展应用(内容与社交场景) 1. **锐博(rybo)**:专业博客文章发布系统,支持分类标签、SEO优化。 2. **锐信(ryxin)**:通用信息发布平台,适用于公告、招聘、活动通知等。 3. **锐态(ryty)**:基于兴趣的陌生人动态社交应用,助力社区活跃。 4. **锐购(rygo)**:商品展示与交易系统,支持虚拟/实物商品发布。 5. **锐游(ryyo)**:游戏爱好者聚集地,支持组队、攻略分享与实时交流。 6. **锐销(ryxl)**:促销活动发布应用,是内容商引流的法宝,每个活动可定制6个与活动主题相关的广告,如果内容商从A平台投放广告为该活动页面引流,然后再将该活动页的6个广告位以更低的价格转售给广告商,比如转售价格是买入价格的1/2或者1/5,那么广告商相当于以成本价的1/2或者1/5获得A平台的广告流量,这样内容商就可以源源不断地用广告商的钱从A平台投放广告为自己的活动页面引流。 7. **锐盘(rypan)**:可创收网盘服务,用户可上传、分享文件,通过展现广告获得收益。 以上的应用都支持通过锐泡(内容商自己的广告位,可出租也可展现自己的广告)展现内容商的广告从而实现为内容商盈利。 ### 扩展工具(内容创作与分发增强) 1. **锐说(rysa)**:字说动画制作工具,将文字自动转为短视频,适合知识类博主。 2. **锐拼(rypin)**:比拼类互动动画生成器,可用于投票、PK、挑战赛等内容营销。 3. **锐发(ryfa)**:多平台一键发布工具,支持将文章同步至头条号、百家号、B站专栏等主流自媒体平台,极大提升内容分发效率。 4. **锐泡(rypo)**:内容商自己的广告位,可出租也可展现自己的广告,内容商的广告位三方收益分成:内容商=85%,运营商=10%,发行商=5%。 > **⚠️ 注**:所有扩展模块的高级功能均需运营商向发行商付费激活后,其平台上的内容商(用户)方可使用。 ## 三、创新盈利模式:三方共赢的分润机制 锐鸥构建了一套精细、透明且激励性强的多级分润体系,覆盖运营商、内容商、广告商与推广者四大角色: 1. **运营商付费解锁功能** - 发行商:80%–100% - 推广者(运营商上级):20%(可通过付费提升至50%) 2. **内容商购买增值服务(如道具、工具使用)** - 发行商:40% - 运营商:40%–60% - 推广者(内容商上级):20%(可通过付费提升至50%,发行商比例相应下调) 3. **广告商投放广告** - 发行商:40% - 运营商:40%–60% - 内容商:20%(若广告在其内容页展示/点击,可通过付费提升至50%,发行商比例相应下调) 该机制不仅保障了发行方的可持续投入,更激励运营商积极拓展用户、内容商专注创作优质内容,形成良性商业闭环。 ### 扩展应用运营商价格表 1. **开通锐博(rybo)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 2. **开通锐信(ryxin)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 3. **开通锐态(ryty)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 4. **开通锐购(rygo)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 5. **开通锐游(ryyo)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 6. **开通锐销(ryxl)等级**:0级=免费,1级=68元,2级=168元,3级=368元,4级=568元,5级=868元。 7. **开通锐盘(rypan)等级**:0级=免费。 ### 扩展应用内容商价格表 #### 1. 锐博(rybo) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可发1篇博文,500字/篇,图片0张,0个类目 | 2元/月,每天可发2篇博文,800字/篇,图片3张/篇,2个类目 | 4元/月,每天可发4篇博文,1200字/篇,图片6张/篇,4个类目 | 6元/月,每天可发4篇博文,1800字/篇,图片9张/篇,6个类目 | #### 2. 锐信(ryxin) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可发1条信息,500字/条,图片0张/条 | 2元/月,每天可发2条信息,800字/条,图片3张/条 | 4元/月,每天可发4条信息,1200字/条,图片6张/条 | 6元/月,每天可发6条信息,1800字/条,图片9张/条 | #### 3. 锐态(ryty) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可发1条动态,500字/条,图片0张/条 | 2元/月,每天可发2条动态,800字/条,图片3张/条 | 4元/月,每天可发4条动态,1200字/条,图片6张/条 | 6元/月,每天可发6条动态,1800字/条,图片9张/条 | #### 4. 锐购(rygo) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,可发商品10个,500字/商品,预览图3张/商品,详情图3张/商品,0个类目 | 2元/月,可发商品20个,800字/商品,预览图6张/商品,详情图6张/商品,2个类目 | 4元/月,可发商品40个,1200字/商品,预览图9张/商品,详情图9张/商品,4个类目 | 6元/月,可发商品60个,1800字/商品,预览图9张/商品,详情图12张/商品,6个类目 | #### 5. 锐游(ryyo) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可发1条游戏动态,500字/条,图片0张/条,游戏组队20次/天 | 2元/月,每天可发2条游戏动态,800字/条,图片3张/条,游戏组队40次/天 | 4元/月,每天可发4条游戏动态,1200字/条,图片6张/条,游戏组队60次/天 | 6元/月,每天可发6条游戏动态,1800字/条,图片9张/条,游戏组队80次/天 | #### 6. 锐销(ryxl) | 0级 | 1级 | 2级 | 3级 | 4级 | 5级 | |:---:|:---:|:---:|:---:|:---:|:---:| | 免费,可发1个促销活动,500/活动,图片0张 | 2元/月,可发2个促销活动,800字/活动,图片3张/活动 | 4元/月,可发4个促销活动,1200字/活动,图片6张/活动 | 6元/月,可发6个促销活动,1800字/活动,图片9张/活动 | 8元/月,可发8个促销活动,2400字/活动,图片12张/活动 | 10元/月,可发10个促销活动,字数2800/活动,图片16张/活动 | #### 7. 锐盘(rypan) | 0级 | |:---:| | 免费,上传文件数量不限,保存天数不限 | ### 扩展工具运营商价格表 1. **开通锐说(rysa)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 2. **开通锐拼(rypin)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 3. **开通锐发(ryfa)等级**:0级=免费,1级=68元,2级=168元,3级=368元。 4. **开通锐泡(rypo)等级**:0级=免费,1级=68元,2级=168元,3级=368元,4级=568元,5级=868元。 ### 扩展工具内容商价格表 #### 1. 锐说(rysa) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可创建锐说动画1个,时长3分钟/个 | 2元/月,每天可创建锐说动画2个,时长10分钟/个 | 4元/月,每天可创建锐说动画3个,时长15分钟/个 | 6元/月,每天可创建锐说动画4个,时长20分钟/个 | #### 2. 锐拼(rypin) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,每天可创建锐拼动画1个,时长3分钟/个 | 2元/月,每天可创建锐拼动画2个,时长10分钟/个 | 4元/月,每天可创建锐拼动画3个,时长15分钟/个 | 6元/月,每天可创建锐拼动画4个,时长20分钟/个 | #### 3. 锐发(ryfa) | 0级 | 1级 | 2级 | 3级 | |:---:|:---:|:---:|:---:| | 免费,一篇文章或视频可发布到2个自媒体平台 | 2元/月,一篇文章或视频可发布到4个自媒体平台 | 4元/月,一篇文章或视频可发布到6个自媒体平台 | 6元/月,一篇文章或视频可发布到8个自媒体平台 | #### 4. 锐泡(rypo) | 0级 | 1级 | 2级 | 3级 | 4级 | 5级 | |:---:|:---:|:---:|:---:|:---:|:---:| | 免费,可创建弹窗广告位1个,普通广告位2个 | 2元/月,可创建弹窗广告位2个,普通广告位4个 | 4元/月,可创建弹窗广告位3个,普通广告位8个 | 6元/月,可创建弹窗广告位4个,普通广告位12个 | 8元/月,可创建弹窗广告位4个,普通广告位16个 | 10元/月,可创建弹窗广告位6个,普通广告位20个 | PS: 扩展应用与扩展工具价格表可能会不定期调整,请留意发行商官网的通告。 ## 四、当前进展与未来展望 目前,锐鸥由锐白个人独立开发,因工程量庞大,开发进度相对缓慢。目前只上线部分应用与工具,其余扩展应用与扩展工具正在有序开发中,后续将逐步上线。 为加速产品迭代与生态建设,锐码工作室现正寻求种子轮融资。我们诚邀对SaaS工具、内容平台、Web3.0基础设施或创作者经济赛道感兴趣的机构参与合作。 - **📩 投资洽谈联系邮箱**:[rymaa_cn@163.com](mailto:rymaa_cn@163.com) - **📧 邮件主题格式**:`锐鸥(ryo)投资意向洽谈-投资机构名称` ## 五、安全声明:严禁破解与篡改 锐鸥高度重视知识产权与系统安全。严禁任何个人、企业或黑客对代理端进行反编译、破解、修改或二次分发。发行商将通过程序自检、人工审核及用户举报等多渠道监控合规性。一经查实违规行为,将依法追责并处以高额罚金;同时,举报者可获得处罚金20%作为奖励。 每个运营商开放的应用等级与工具等级,都可以在发行商的官网通过运营商的网站域名进行查询,如果举报者发现运营商有违规行为,可以在发行商的官网进行举报,发行商对运营商进行高额处罚后将处罚金的20%奖励给举报者。欢迎大家踊跃监督,共建良好生态环境。 --- **锐鸥(ryo)——不止是建站工具,更是下一代内容生态的操作系统。** 无论你是想打造垂直社区、个人品牌站,还是区域服务平台,锐鸥都为你提供“开箱即用+按需付费+收益共享”的全新可能。 未来已来,只待共建。 ============================== # 版权声明 客户端浏览器加载的 ryo.js 脚本文件采用 锐码署名传播许可证(RSPL) 授权。详情请见 LICENSE 或 LICENSE-EN 文件。 ## 以下是许可证的内容 ============================== # 锐码署名传播许可证 ## 版本 1.0 ### 前言 本许可证旨在让您可以自由地使用、修改和分发本软件及其衍生作品,无论是用于个人、内部或商业目的。作为交换,我们要求您在软件的任何公开可见的界面中,给予原始作者适当的署名。我们希望这个小小的要求能帮助更多人了解并使用我们的作品。 ### 条款与条件 在遵守下列条件的前提下,您被永久授权免费使用、复制、修改、合并、出版、分发、再授权和/或销售本软件及其衍生作品的副本。 #### 核心要求:署名必须传播 **1. 当软件以“交互式应用程序”模式分发或使用时:** **1.1 定义**:“交互式应用程序”指任何直接向最终用户提供图形用户界面或命令行界面的软件。 **1.2 图形界面要求**:必须在应用程序的某个显著位置(例如:“关于”、“帮助”菜单或主设置页面)提供一个名为 “关于版权”或“About Copr” 或类似含义的按钮或链接。点击此处必须弹出一个对话框或页面,清晰、完整地显示本软件的版权信息。此信息必须至少包括: - **1.2.1** 原始作者的姓名/名称和版权声明。 - **1.2.2** 指向原始源代码仓库的链接(如果存在)。 - **1.2.3** 本许可证的名称和链接。 **1.3 命令行界面要求**:必须提供一个命令行参数(例如:-C 或 --copr),当用户执行此命令时,必须在标准输出中清晰、完整地显示上述版权信息。 **2. 当软件以“嵌入式库”模式分发或使用时:** **2.1 定义**:“嵌入式库”指其功能被整合到另一个“宿主程序”中,且不直接向最终用户暴露其自身界面的软件。 **2.2 无界面宿主程序**:如果宿主程序本身没有图形用户界面(例如:嵌入式系统、无头服务、后台守护进程、家电控制固件),则无需显示此署名信息。 **2.3 有界面宿主程序**:如果宿主程序拥有图形用户界面,则必须遵守第1条中的图形界面要求。即,宿主程序必须在它的“关于”或类似界面中,包含本软件的版权信息。该信息可以与其他组件的版权信息并列展示。 **3. 源代码级别的要求:** **3.1** 在您分发的任何修改后的本软件源代码中,必须在原文件的版权声明旁边,保留所有原始的版权声明和协议文本。 **3.2** 您可以在原始声明之后,添加您自己的修改版权声明。 **4. 其他规定** **4.1 免责声明**:本软件按“原样”提供,不提供任何明示或暗示的担保,包括但不限于适销性、特定用途适用性及不侵权的担保。 **4.2 协议变更**:原始版权所有者可以发布此协议的新版本。您可以选择使用本许可证的任一版本,但您分发的软件必须遵守该版本的条款。 ============================== 之所以要编写一个全新的开源许可证,是因为 MIT 不太适合自己的需求,我想要的是那种既可以让别人无任何限制使用(免费、商用、开源、闭源、修改、分发),又能有效地推广自己的开源程序的许可证,于是写了这个《锐码署名传播许可证》。对于使用《锐码署名传播许可证》发布的开源程序,大家完全可以像 MIT 那样使用,唯一的区别是要求在有图形界面的终端程序中显示源程序的版权信息。 另外,锐白开发的系列程序(锐派(Python类应用)、锐安(安卓类应用)、锐杰(JS类应用))都会使用一种全新的结构化数据标记语言:逗点对象,使用逗点对象可以很方便在终端、手机端、网页端进行各种配置数据的编辑修改,也方便构建领域专用语言(DSL),逗点对象简介如下: ============================== # 逗点对象:极简、高效的移动端数据标记语言 在移动设备上输入结构化数据,如 JSON 或 XML,往往需要频繁切换键盘、输入括号和引号,操作繁琐且易出错。为解决这一痛点,锐白设计了一种极简、高效的数据格式——逗点对象(Comma Period Object, CPO)。它仅使用英文句点 . 和逗号 , 作为语法符号,无需引号、括号或冒号,极大降低了手机输入的复杂度,特别适用于快速编辑对象数据或构建轻量级标记语言。 ## 语法设计:极简至上 逗点对象的核心语法规则极为简单: - **对象开始**:`.,` - **对象结束**:`,.` - **属性定义**:`.key value` - **数组开始**:`..,` - **数组结束**:`,,.` - **嵌套对象**:`.key ., ... ,.` 例如,一个包含位置和尺寸的矩形对象可表示为: ., .x 100 .y 50 .w 200 .h 100 .t rect ,. 整个过程无需切换键盘,只需在英文输入法下连续输入 . 和 , 配合空格和数字,即可完成结构化数据的录入,效率远超传统格式。 ## 核心优势:为移动端而生 逗点对象的最大优势在于其极致的输入友好性。在手机上,用户无需频繁点击符号键盘寻找 {}、[]、" 或 :,只需使用最易触及的 . 和 , 键,配合空格分隔,即可完成复杂数据的构建。这使得它非常适合以下场景: - **快速原型设计**:设计师或开发者在移动端快速记录 UI 元素的坐标、尺寸等属性。 - **配置文件编辑**:用户通过手机编辑简单的应用配置,如界面布局、快捷指令等。 - **日志或笔记标记**:用结构化方式记录带属性的笔记,如 `.t meeting .m Discuss project timeline .x 1 .y 2`。 ## 扩展为属性标记语言 逗点对象不仅是一种数据格式,更可扩展为一种属性标记语言(Attribute Markup Language)。通过约定特定的属性名称,可以构建领域专用语言(DSL)。例如: - `.x, .y, .z`:表示三维空间坐标。 - `.w, .h, .d`:表示宽度、高度、深度。 - `.t`:类型(type),如 button, text, image。 - `.n`:名称(name),用于标识对象。 - `.m`:消息(message),附加提示或说明。 - `.s`:显示(show),控制可见性。 - `.c`:选择(choose),表示当前选择状态。 - `.a`:动作(action),绑定点击或事件。 - `.o`:子对象(object),用于嵌套组合。 利用这些属性,我们可以描述一个复杂的 UI 组件: ., .t button .n submit .x 150 .y 300 .w 100 .h 40 .s true .c false .a clickSubmit .m Click to submit form .o ., .t icon .x 10 .y 10 .w 20 .h 20 ,. ,. 这表示一个提交按钮,包含位置、尺寸、状态、动作和一个图标子元素。通过解析,可直接映射为程序中的对象模型。 ## 可逆性与兼容性 逗点对象设计了双向转换函数 `sto`(string to object,字符串转对象)和 `ots`(object to string,对象转字符串),确保数据可逆。`sto` 能正确解析 TRUE/FALSE 为布尔值,NULL 为空值,EMPTY 为空串,并忽略函数;`ots` 支持美化输出,当指定缩进时可生成多行易读格式,缩进为 0 时则压缩为单行,便于传输。整个实现使用 ES3 语法,兼容所有浏览器,包括老旧设备。 ## 结语 逗点对象以其极简的符号系统和高效的输入体验,为移动端数据编辑提供了一种优雅的解决方案。它不仅是 JSON 的轻量替代,更可通过属性约定演变为强大的标记语言,适用于配置、UI 描述、笔记标记等多种场景。在追求效率与简洁的今天,逗点对象展现了一种“少即是多”的设计哲学,是移动优先时代下值得推广的数据表达方式。 在锐鸥(ryo.js)中,逗点对象的源码如下,如有错误欢迎指正: ```javascript obj: function(A, B, C, D) { var a, b, c, d, l, s, k, v, o, z; A = A || ''; B = B || 1; C = C || '`'; D = D || 0; if (B == 1) { if (typeof A == 'object') return A; if (!A || typeof A != 'string') return null; A = A.trim(); a = A.substr(0, 2); if (a == '{"') return JSON.parse(A); if (a == '.,') return this.sto(A); a = A.split(C); l = a.length; o = {}; for (z = 0; z < l; z += 2) { k = this.e36(a[z], 2); v = this.e36(a[z + 1], 2); if (!k) continue; o[k] = v; } return o; } else { if (typeof A == 'string') return A; if (typeof A == 'number') return A + ''; if (!A || typeof A != 'object') return ''; if (typeof A == 'object' && C == 1) return JSON.stringify(A); if (typeof A == 'object' && C == 2) return this.ots(A, D); s = []; for (z in A) { s.push(this.e36(z, 1), this.e36(A[z], 1)); } s = s.join(C); return s; } }, // comma period object cpo: function(A, B=1, C=0) { if(B == 1) return this.sto(A); return this.ots(A, C); }, // string to object sto: function(str) { var i = 0; var len = str.length; function skipWhitespace() { while (i < len && ' \t\n\r'.indexOf(str.charAt(i)) !== -1) i++; } function parseValue() { skipWhitespace(); if (i >= len) return undefined; // 数组开始 .., if (str.substr(i, 3) === '..,') { i += 3; return parseArray(); } // 对象开始 ., if (str.substr(i, 2) === '.,') { i += 2; return parseObject(); } // 普通值 var start = i; while (i < len) { var char = str.charAt(i); // 只有在遇到新的键开始时才结束(空格 + . + 非分隔符) if (char === ' ' || char === '\t' || char === '\n' || char === '\r') { // 检查后面是否是新的键开始:空格后紧跟 . 且 . 后不是分隔符 var j = i; while (j < len && ' \t\n\r'.indexOf(str.charAt(j)) !== -1) j++; if (j < len && str.charAt(j) === '.' && j + 1 < len && ' .,\t\n\r'.indexOf(str.charAt(j + 1)) === -1) { break; // 遇到新的键,结束当前值 } } // 遇到数组结束标志 if (str.substr(i, 3) === ',,.') { break; } // 遇到逗号分隔符(在数组中) if (char === ',') { break; } i++; } var val = str.substring(start, i).trim(); // 类型还原 if (val === 'TRUE') return true; if (val === 'FALSE') return false; if (val === 'NULL') return null; if (val === 'EMPTY' || val === '') return ''; // 尝试转数字 if (/^-?\d+$/.test(val)) { return parseInt(val, 10); } if (/^-?\d*\.\d+$/.test(val)) { return parseFloat(val); } return val; } function parseObject() { var obj = {}; skipWhitespace(); while (i < len) { skipWhitespace(); if (i >= len) break; // 检查对象结束标志 ',.' if (str.substr(i, 2) === ',.') { i += 2; return obj; } // 必须是 '.' 开头,且 '.' 前必须是空白或起始位置 if (str.charAt(i) !== '.') { i++; continue; } // 检查 '.' 前是否为空白或起始位置 if (i > 0 && ' \t\n\r'.indexOf(str.charAt(i - 1)) === -1) { // 前面不是空白,说明是如 abc.key 中的 '.',不是键名 i++; continue; } i++; // 跳过 '.' // 关键:不允许 . 和 key 之间有空格 // 检查是否已到结尾或下一个字符是分隔符(即 key 为空) if (i >= len || ' .,\t\n\r'.indexOf(str.charAt(i)) !== -1) { // key 为空,跳过 continue; } // 提取 key 名称:连续非空白、非分隔符 var start = i; while (i < len && ' .,\t\n\r'.indexOf(str.charAt(i)) === -1) { i++; } var key = str.substring(start, i); if (!key) continue; // 此时 i 指向 key 后的第一个分隔符(空格、.、, 等) skipWhitespace(); // 跳过 key 后的空白 if (i >= len) break; // 解析值 var value; if (str.substr(i, 3) === '..,') { i += 3; value = parseArray(); } else if (str.substr(i, 2) === '.,') { i += 2; value = parseObject(); } else { value = parseValue(); } obj[key] = value; skipWhitespace(); } return obj; } function parseArray() { var arr = []; skipWhitespace(); while (i < len) { skipWhitespace(); if (i >= len) break; // 检查数组结束标志 ',,.' if (str.substr(i, 3) === ',,.') { i += 3; return arr; } // 数组元素之间用逗号分隔 if (str.charAt(i) === ',') { i++; skipWhitespace(); continue; } // 解析数组元素(可能是基础值、对象或子数组) var value; if (str.substr(i, 3) === '..,') { i += 3; value = parseArray(); } else if (str.substr(i, 2) === '.,') { i += 2; value = parseObject(); } else { value = parseValue(); } arr.push(value); skipWhitespace(); } return arr; } skipWhitespace(); if (str.substr(i, 2) === '.,') { i += 2; return parseObject(); } return {}; }, // object to string ots: function(obj, indent=0) { var a, l, n, k, v, that = this; l = 0; indent = parseInt(indent); n = indent ? '\n' : ' '; function arr2str(A, B=0, C=' ') { var a, e, l, n, k, v, z; a = []; l = B; n = C; for(z = 0; z < A.length; z++) { v = A[z]; t = typeof v; if(t == 'function') continue; else if(Array.isArray(v)) { a.push(that.pc(' ', (l+1)*indent) +'.'+k+' ..,'); s = arr2str(v, l+1, n) + n + that.pc(' ', (l+1)*indent) + ',,.'; a.push(s); } else if(t == 'object') { a.push(that.pc(' ', (l+1)*indent) +'.'+k+' .,'); s = obj2str(v, l+1, n) + n + that.pc(' ', (l+1)*indent) + ',.'; a.push(s); } else { if(v == null) v = 'NULL'; else if(t == 'string' && !v) v = 'EMPTY'; else if(t == 'boolean') v = v? 'TRUE' : 'FALSE'; if(z < A.length-1) e = ', '; else e = ''; a.push(that.pc(' ', (l+1)*indent) +v+e); } } a = a.join(n); return a; } function obj2str(A, B=0, C=' ') { var a, l, n, k, v; a = []; l = B; n = C; for(k in A) { v = A[k]; t = typeof v; if(t == 'function') continue; else if(Array.isArray(v)) { a.push(that.pc(' ', (l+1)*indent) +'.'+k+' ..,'); s = arr2str(v, l+1, n) + n + that.pc(' ', (l+1)*indent) + ',,.'; a.push(s); } else if(t == 'object') { a.push(that.pc(' ', (l+1)*indent) +'.'+k+' .,'); s = obj2str(v, l+1, n) + n + that.pc(' ', (l+1)*indent) + ',.'; a.push(s); } else { if(v == null) v = 'NULL'; else if(t == 'string' && !v) v = 'EMPTY'; else if(t == 'boolean') v = v? 'TRUE' : 'FALSE'; a.push(that.pc(' ', (l+1)*indent) +'.'+k+' ' + v); } } a = a.join(n); return a; } var str = '.,' +n+ obj2str(obj, 0, n) + n + that.pc(' ', l*indent) + ',.'; return str; },