
Legal Text Format
- 129 installs
- 543 repo stars
- Updated August 5, 2026
- cat-xierluo/legal-skills
Format contracts, clauses, and legal correspondence to court or firm style guides before review, filing, or client delivery from agent-generated drafts.
About
legal-text-format from cat-xierluo/legal-skills standardizes contracts, briefs, and correspondence into professional legal layouts. It guides agents to apply citation rules, section hierarchy, and boilerplate patterns so drafts are review-ready without manual cleanup.
- Enforces legal document structure
- Standardizes clause and heading styles
- Prepares agent drafts for professional review
- Reduces manual reformatting in Word workflows
- Aligns output with firm or court conventions
Legal Text Format by the numbers
- 129 all-time installs (skills.sh)
- Ranked #302 of 688 Office & Documents skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cat-xierluo/legal-skills --skill legal-text-formatAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 129 |
|---|---|
| repo stars | ★ 543 |
| Last updated | August 5, 2026 |
| Repository | cat-xierluo/legal-skills ↗ |
What it does
Format contracts, clauses, and legal correspondence to court or firm style guides before review, filing, or client delivery from agent-generated drafts.
Files
法律文本格式化工具
概述
将法律文本(法律条文或法律案例)转换为规范的 Markdown 格式,删除推广冗余信息,自动识别文本类型并应用相应的格式化规则。
核心职责:只负责格式化和内容清理,不包含内容抓取能力。
与其他技能的协作
典型工作流程
场景:用户请求格式化网页上的法律文本
用户请求 → AI 判断来源 → 抓取类 skill 获取内容 → legal-text-format 格式化示例流程:
1. 用户提供微信公众号链接 → AI 使用 wechat-article-fetch 抓取 → AI 调用 legal-text-format 格式化 2. 用户提供普通网页链接 → AI 使用其他工具抓取 → AI 调用 legal-text-format 格式化 3. 用户直接粘贴文本 → AI 直接调用 legal-text-format 格式化
技能职责边界:
wechat-article-fetch/ 其他抓取工具:负责从各种来源获取原始文本内容legal-text-format:负责对已获取的文本进行格式化和清理
核心原则
内容完整性保证:除格式调整和去除推广内容外,所有法律案例和法条的实质内容必须完整保留,不得有任何遗漏!
工作流程
步骤 1:分析文本类型
使用 LLM 分析输入文本:
- 判断是法律条文还是法律案例
- 识别文本结构特征(章节、条款、案号等)
- 确定适合的格式化策略
- 提取主题用于文件命名
分析提示词参考:
分析以下文本,判断其类型:
- 如果是法律条文:识别章、节、条的结构
- 如果是法律案例:识别案例标题、案号、案情、裁判结果、典型意义等
- 提取主题用于文件命名步骤 2:保存原始内容
将输入的原始内容保存为本地 Markdown 文件:
- 文件位置:
archive/{YYYYMMDD_HHMMSS}_{主题}/ - 文件命名:
{YYYYMMDD}_{主题}_raw.md - 目的:提供溯源依据,便于内容比对验证
归档目录结构示例:
archive/20250122_153400_个人信息保护检察公益诉讼典型案例/
├── 20250122_个人信息保护检察公益诉讼典型案例_raw.md # 原始内容
├── 20250122_个人信息保护检察公益诉讼典型案例_formatted.md # 格式化后的内容(步骤4生成)
└── meta.json # 元信息(可选)步骤 3:格式化文本
重要:一次性处理完整文本,不进行分段。
格式化提示词(参考 examples.md 中的详细示例):
请将以下法律文本格式化为规范的 Markdown 格式。
# 法律条文格式化规则
- 章前面添加二级 markdown 格式(##)
- 不同条文之间添加空行
- 每一条条文内部换行时不应有多余空行
- "第X条"进行加粗(**第X条**)
- 如果一段文字的最后没有句号或分号,则删除后方的回车
- 保持所有条文内容完整,不得遗漏任何条款
# 法律案例格式化规则
- 把英文标点符号替换成中文标点符号(包括括号、逗号、句号、冒号、分号等)
- 案例序号或名称前添加二级 markdown 格式(##),序号后要紧跟案例名称
- 每个案例的章节前添加三级 markdown 格式(###)
- 每个案例的章节内部不应有大于1个的空行(连续换行数不超过2个)
- 清理多余的连续空行,保持段落间适当的分隔
- 把数字格式调整为半角
- 内容范围限定:
- 仅保留从第一个案例到最后一个案例的内容
- 删除前面的文章介绍、作者信息、引言、目录等
- 删除底部的宣传推广内容、二维码、公众号介绍、相关文章推荐等
- 保留标准:只保留案例标题、案号、基本案情、裁判结果、典型意义等法律案例本身的内容
- 保持所有案例实质内容完整,包括案情、裁判、意义等所有部分
# 参考示例
详见 references/examples.md 文件,其中包含4个完整的格式化示例。法律条文格式化规则摘要
- 章前面添加二级 markdown 格式(
##) - 不同条文之间添加空行
- 每一条条文内部换行时不应有多余空行
- "第X条"进行加粗(
**第X条**) - 如果一段文字的最后没有句号或分号,则删除后方的回车
- 保持所有条文内容完整,不得遗漏任何条款
法律案例格式化规则摘要
- 把英文标点符号替换成中文标点符号
- 案例序号或名称前添加二级 markdown 格式(
##),序号后要紧跟案例名称 - 每个案例的章节前添加三级 markdown 格式(
###) - 每个案例的章节内部不应有大于1个的空行(连续换行数不超过2个)
- 清理多余的连续空行,保持段落间适当的分隔
- 把数字格式调整为半角
- 内容范围限定:
- 仅保留从第一个案例到最后一个案例的内容
- 删除前面的文章介绍、作者信息、引言、目录等
- 删除底部的宣传推广内容、二维码、公众号介绍、相关文章推荐等
- 保留标准:只保留案例标题、案号、基本案情、裁判结果、典型意义等法律案例本身的内容
- 保持所有案例实质内容完整,包括案情、裁判、意义等所有部分
步骤 4:保存
保存格式化后的文档:
- 文件位置:
archive/{YYYYMMDD_HHMMSS}_{主题}/ - 文件命名:
{YYYYMMDD}_{主题}_formatted.md - 与
raw.md保存在同一归档目录下
参考文档
格式化示例
详细的格式化示例和对比请参见 examples.md,包含:
- 4个完整的法律案例格式化示例
- 每个示例包含原始文本和格式化后的对比
- 格式化要点总结(标点符号处理、标题层级、空行处理、内容范围等)
准确性要求
- 不改变原文含义:格式调整不得改变法律文本的原意
- 保留关键信息:案号、法院名称、当事人等关键信息必须保留
- 序号保持:案例序号、条文序号不得修改
输出文档结构
归档目录组织
所有格式化结果按时间戳归档存储:
archive/
├── {YYYYMMDD_HHMMSS}_{文档主题}/
│ ├── {YYYYMMDD}_{主题}_raw.md # 原始抓取内容
│ ├── {YYYYMMDD}_{主题}_formatted.md # 格式化后的内容
│ └── meta.json # 元信息(可选)命名规则:
- 目录名:
{YYYYMMDD_HHMMSS}_{主题}(例:20250122_153400_个人信息保护典型案例) - 文件名:
- 原始文件:
{YYYYMMDD}_{主题}_raw.md(例:20250122_个人信息保护典型案例_raw.md) - 格式化文件:
{YYYYMMDD}_{主题}_formatted.md(例:20250122_个人信息保护典型案例_formatted.md) - 主题限制:从文本中提取的核心主题,限制30字以内
- 日期格式:
YYYYMMDD(例:20250122)
formatted.md 内容结构
# {文档标题}
## 元信息
- **原文链接**:{从原始文件的 `> 原文链接:` 行提取,无则省略此行}
- **处理时间**:{时间戳}
- **文本类型**:{法律条文/法律案例}
---
{格式化后的正文内容}原文链接提取规则:当输入来自 wechat-article-fetch 时,原始 Markdown 文件头部包含 > 原文链接: https://mp.weixin.qq.com/s/xxxxx,必须提取该 URL 写入元信息的"原文链接"字段。
质量标准
- 标点符号统一:所有标点符号使用中文标点
- 数字格式统一:数字使用半角字符
- 层级结构清晰:正确使用二级、三级标题
- 空行规范:段落间空行适当,不过多也不缺失
- 内容完整性:保留所有法律相关内容,去除无关推广信息
适用场景
- 整理法律条文汇编
- 规范化法律案例集
- 准备法律学习材料
- 建立法律文本知识库
- 清理从网页抓取的法律文本
输入要求
本技能接受以下类型的输入:
1. 已抓取的文本内容:由其他 skill(如 wechat-article-fetch)获取的文本 2. 用户粘贴的文本:用户直接提供的文本内容 3. 本地文件:已保存的 Markdown/文本文件
不接受:网页链接(链接应由专门的抓取类 skill 处理)
来自 wechat-article-fetch 的自动调用
当 wechat-article-fetch 检测到法律内容且本技能已安装时,会自动链式调用本技能。此时输入为已保存的 Markdown 文件路径。处理流程不变:
1. 读取指定路径的 Markdown 文件内容作为输入 2. 按步骤 1-4 执行(分析类型、保存原始、格式化、验证) 3. 结果保存到本技能的 archive/ 目录 4. 文件路径记录在 formatted.md 元信息的"来源"字段中
更新日志
[1.2.1] - 2026-04-20
改进
- 📝 明确接受来自
wechat-article-fetch的文件路径作为输入来源 - 📝 在输入要求章节补充自动调用场景说明
---
[1.2.0] - 2026-04-20
确认
- ✅ 内置 Archive 机制:归档目录已内置于 skill 内部
archive/{YYYYMMDD_HHMMSS}_{主题}/ - ✅ 自包含存储:原始内容和格式化结果都保存在 skill 目录内
- ✅ 完整结构:
archive/
└── 20260420_种业知识产权典型案例/
├── 20260420_种业知识产权典型案例_raw.md
└── 20260420_种业知识产权典型案例_formatted.md技术细节
- 原始文件:
{YYYYMMDD}_{主题}_raw.md - 格式化文件:
{YYYYMMDD}_{主题}_formatted.md - 元信息可选保存在
meta.json
---
[1.1.0] - 2026-01-22
新增
- ✨ 采用 archive 归档结构,按时间戳组织输出
- ✨ 文件命名包含日期和主题信息,减少用户重命名需求
改进
- 📝 输出目录从
outputs/formatted-legal-texts/改为archive/ - 📝 文件命名规则优化:
- 原始文件:
{YYYYMMDD}_{主题}_raw.md - 格式化文件:
{YYYYMMDD}_{主题}_formatted.md - 📝 目录命名:
{YYYYMMDD_HHMMSS}_{主题}/ - 🔧 添加详细的归档目录结构说明
- 🔧 更新元信息中的原始文件引用格式
技术细节
- 参考
mineru-ocr的 archive 结构设计 - 主题限制30字以内,便于文件名显示
- 日期格式统一为
YYYYMMDD
---
[1.0.0] - 2026-01-22
新增
- ✨ 法律文本格式化功能,支持法律条文和法律案例两种类型
- ✨ 自动文本类型识别和分析
- ✨ 粘贴文本输入支持
- ✨ 原始内容保存和溯源机制
- ✨ 内容完整性验证功能
- ✨ 推广冗余信息自动清理
- ✨ 详细的格式化示例文档(references/examples.md)
改进
- 📝 完整的技能文档,包含工作流程和质量标准
- 🔧 职责分离设计:本技能专注格式化和清理,不包含抓取能力
- 🔧 明确技能职责边界和输入要求
- 🔧 与抓取类 skill(如 wechat-article-fetch)的 AI 自主协作
- 🔧 添加详细的格式化提示词,包含 4 个完整示例对比
- 🔧 Progressive Disclosure 设计:核心规则在 SKILL.md,详细示例在 references
技术细节
- 实现 LLM 驱动的文本类型自动识别
- 建立原始内容与格式化结果的验证机制
- 定义法律条文和法律案例的格式化规则
- 单一职责原则:格式化与抓取能力解耦
- 添加经过实践验证的格式化提示词和示例
- 使用 references 目录存储详细示例,保持 SKILL.md 简洁
待办事项
- [ ] 添加更多法律文本类型支持(如裁判文书、法律法规汇编等)
- [ ] 优化格式化规则的准确性
- [ ] 添加批量处理功能
Creative Commons Attribution-NonCommercial 4.0 International
Copyright (c) 2025 杨卫薪律师(微信ywxlaw)
=======================================================================
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.
You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
Under the following terms:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
- NonCommercial — You may not use the material for commercial purposes.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
To view a copy of this license, visit:
https://creativecommons.org/licenses/by-nc/4.0/
=======================================================================
Commercial License
For commercial use licenses, please contact:
Email: secretxierluo@gmail.com
WeChat: ywxlaw (微信)
=======================================================================
The full text of the CC BY-NC 4.0 license is reproduced below:
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING
FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Section 1 – Definitions.
Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
Copyright and Similar Rights means copyright and/or similar rights closely related to copyright, including without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
Licensor means the individual(s) or entity(ies) granting rights under this Public License.
NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 – Scope.
Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
a) reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
b) produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
Term. The term of this Public License is specified in Section 6(a).
Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
Downstream recipients. Each recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by the Licensor or others designated as receiving attribution as provided in Section 3(a)(1)(A)(i).
Other rights. Moral rights, rights against unfair competition, rights to protect publicity, privacy, or personality rights, and any other rights other than Copyright and Similar Rights are not subject to this Public License. Additional rights may apply to the Licensed Material, such as patent, trademark, or other intellectual property rights.
Section 3 – License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
Attribution.
If You Share the Licensed Material (including in modified form), You must:
a) retain the following if it is supplied by the Licensor with the Licensed Material:
i) identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
ii) a copyright notice;
iii) a notice that refers to this Public License;
iv) a notice that refers to the disclaimer of warranties;
v) a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
b) indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
c) indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
If requested by the Licensor, You must remove any of the information required by Section 3(a)(1) to the extent reasonably practicable.
NonCommercial. You may not exercise the Licensed Rights for commercial purposes.
Section 4 – Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
a) for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; and
b) if You include all or a substantial portion of the contents of the database in a database to which You have Adapted Material, then You must comply with Section 3(a) if You Share the Adapted Material.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 – Disclaimer of Warranties and Limitation of Liability.
Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or out of the use or inability to use the Licensed Material, even if the Licensor has been advised of the possibility of any such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
Section 6 – Term and Termination.
a) This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically and are reverted.
b) Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation.
c) For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
d) Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 – Other Terms and Conditions.
a) The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
b) Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 – Interpretation.
a) For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
b) If any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable.
c) If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
d) No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
e) Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
=======================================================================
Creative Commons may be contacted at creativecommons.org.
法律文本格式化示例
本文档提供详细的格式化示例,用于指导 LLM 进行准确的文本格式化。
案例格式化示例 1
原始文本
首例汇校他人作品的著作权纠纷案
——钱某书、某文学出版社与胥某芬、某文艺出版社著作权纠纷案
一审:上海市中级人民法院(1993)沪中民初字第35号
二审:上海市高级人民法院(1995)沪高民(知)终字第7号
案情摘要
《围城》一书的作者原告钱某书发现被告胥某芬、被告某文艺出版社未经其同意,对《围城》进行汇校并予出版,侵害了自己对《围城》一书的演绎权和出版使用权,故诉至法院,请求判令胥某芬、某文艺出版社停止侵权、赔偿损失,并在全国性报纸上公开赔礼道歉。
裁判结果
一审法院经审理认为,胥某芬未经著作权人同意,对《围城》进行汇校,某文艺出版社出版《围城》汇校本,共同侵害了钱某书就作品《围城》享有的著作权。格式化后
## 首例汇校他人作品的著作权纠纷案
——钱某书、某文学出版社与胥某芬、某文艺出版社著作权纠纷案
一审:上海市中级人民法院(1993)沪中民初字第35号
二审:上海市高级人民法院(1995)沪高民(知)终字第7号
### 案情摘要
《围城》一书的作者原告钱某书发现被告胥某芬、被告某文艺出版社未经其同意,对《围城》进行汇校并予出版。
### 裁判结果
一审法院经审理认为,胥某芬未经著作权人同意案例格式化示例 2
原始文本
01
微某公司诉简某公司等不正当竞争纠纷案
——未经授权调用服务器API接口获取数据构成不正当竞争
基本案情
微某公司是新浪微博的经营者,简某公司及其深圳分公司是iDataAPI网站经营者。iDataAPI用户可通过网站提供的API(应用程序编程接口)获取大量新浪微博数据。
裁判结果
广东省高级人民法院生效判决认为,微某公司对依法依规持有的微博数据享有自主管控、合法利用并获取经济利益的权益。
典型意义
数据是数字经济高质量发展的"石油",是加快发展新质生产力、提升全要素生产率的重要基础资源。格式化后
## 01 微某公司诉简某公司等不正当竞争纠纷案——未经授权调用服务器API接口获取数据构成不正当竞争
### 基本案情
微某公司是新浪微博的经营者,简某公司及其深圳分公司是iDataAPI网站经营者。iDataAPI用户可通过网站提供的API(应用程序编程接口)获取大量新浪微博数据。
### 裁判结果
广东省高级人民法院生效判决认为,微某公司对依法依规持有的微博数据享有自主管控、合法利用并获取经济利益的权益。
### 典型意义
数据是数字经济高质量发展的"石油",是加快发展新质生产力、提升全要素生产率的重要基础资源。案例格式化示例 3
原始文本
案例一
首例大数据搬家软件不正当竞争案
——公开数据权益归属及不正当数据利用行为的认定
【案号】
(2021)粤0192民初1692号/(2023)粤73民终995号[浙江天某网络有限公司、浙江淘某网络有限公司诉广州锐某信息科技有限公司等不正当竞争纠纷案]
【案情与裁判】
广州锐某信息科技有限公司(以下简称锐某公司)开发运营"铺货易""代销易"软件,按权限等级、服务周期不同在拼多多服务市场内宣传销售.
【典型意义】
本案系全国首例涉电商平台商品大数据不正当竞争案。本案裁判通过有效规范大数据不正当利用行为,有助于健全数据治理规则,发挥司法赋能数据产业发展的积极效能。格式化后
## 案例一 首例大数据搬家软件不正当竞争案——公开数据权益归属及不正当数据利用行为的认定
### 【案号】
(2021)粤0192民初1692号/(2023)粤73民终995号[浙江天某网络有限公司、浙江淘某网络有限公司诉广州锐某信息科技有限公司等不正当竞争纠纷案]
### 【案情与裁判】
广州锐某信息科技有限公司(以下简称锐某公司)开发运营"铺货易""代销易"软件,按权限等级、服务周期不同在拼多多服务市场内宣传销售。
###【典型意义】
本案系全国首例涉电商平台商品大数据不正当竞争案。本案裁判通过有效规范大数据不正当利用行为,有助于健全数据治理规则,发挥司法赋能数据产业发展的积极效能。案例格式化示例 4
原始文本
6
浙江某生物技术有限公司与某生物医药股份有限公司技术秘密许可使用合同纠纷案
【案例索引】
一审:杭州中院(2018)浙01民初4088号
二审:最高法院(2021)最高法知民终955号
【入选理由】
本案系因干细胞及免疫细胞制备、运输、存储、保管、复苏及质控技术,干细胞库及免疫系统储存库建设、运行和管理技术等硬件建设等引起的技术秘密许可使用合同纠纷,涉及生物医药中的高精尖问题,法律关系复杂。
【裁判要旨】
在技术许可合同中,交付方主张其交付了技术资料,应当承担举证证明责任。在合同对交付方应当履行的交付内容和期限有明确约定的情况下,应结合涉案合同约定审查判断交付方是否已经履行了交付相关技术资料的合同义务。
【简要案情】
2015年8月27日,甲方(许可方)浙江某生物技术有限公司、乙方(被许可方)某生物医药股份有限公司和丙方陆某、王某签订《技术授权许可协议》,就某生物医药股份有限公司(包括其子公司等关联实体)在地域范围内使用浙江某生物技术有限公司以下技术相关的包括技术秘密等在内的所有知识产权达成合意。格式化后
## 6 浙江某生物技术有限公司与某生物医药股份有限公司技术秘密许可使用合同纠纷案
### 【案例索引】
一审:杭州中院(2018)浙01民初4088号
二审:最高法院(2021)最高法知民终955号
### 【入选理由】
本案系因干细胞及免疫细胞制备、运输、存储、保管、复苏及质控技术,干细胞库及免疫系统储存库建设、运行和管理技术等硬件建设等引起的技术秘密许可使用合同纠纷,涉及生物医药中的高精尖问题,法律关系复杂。
### 【裁判要旨】
在技术许可合同中,交付方主张其交付了技术资料,应当承担举证证明责任。在合同对交付方应当履行的交付内容和期限有明确约定的情况下,应结合涉案合同约定审查判断交付方是否已经履行了交付相关技术资料的合同义务。
### 【简要案情】
2015年8月27日,甲方(许可方)浙江某生物技术有限公司、乙方(被许可方)某生物医药股份有限公司和丙方陆某、王某签订《技术授权许可协议》,就某生物医药股份有限公司(包括其子公司等关联实体)在地域范围内使用浙江某生物技术有限公司以下技术相关的包括技术秘密等在内的所有知识产权达成合意。格式化要点总结
标点符号处理
- 所有英文标点符号替换成中文标点符号
- 括号:( ) → ()
- 逗号:, → ,
- 句号:. → 。
- 冒号:: → :
- 分号:; → ;
标题层级
- 案例序号或名称前添加二级 markdown 格式(##)
- 案例序号后要紧跟案例名称
- 每个案例的章节前添加三级 markdown 格式(###)
空行处理
- 每个案例的章节内部不应有大于1个的空行(连续换行数不超过2个)
- 清理多余的连续空行,保持段落间适当的分隔
内容范围
- 仅保留从第一个案例到最后一个案例的内容
- 删除前面的文章介绍、作者信息、引言、目录等
- 删除底部的宣传推广内容、二维码、公众号介绍、相关文章推荐等
内容完整性
- 保持所有案例实质内容完整,包括案情、裁判、意义等所有部分
- 不改变原文含义
- 案号、法院名称、当事人等关键信息必须保留
#!/usr/bin/env python3
"""
Final comprehensive fix for all 9 formatted legal case files.
Addresses:
1. Lines like "侵害XXX案" -> "## 侵害XXX案" (case titles without header)
2. Fix "## **典型案例**" (wrong first case header)
3. Remove "**目录**", "**典型案例**" scope artifacts that should not appear as headers
4. Restore __URL_PLACEHOLDER__ back to original URLs
"""
import re
import os
def final_fix(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Restore URL placeholders to actual URLs
# Find them in the content
url_pattern = r'__URL_PLACEHOLDER_(\d+)__'
urls_found = {}
for m in re.finditer(url_pattern, content):
idx = int(m.group(1))
# The URL was: https://mp.weixin.qq.com/s?__biz=MzA3MjcxNDM5OQ==...
# We stored the placeholder when we saw the URL, but we need to restore it
# The placeholder was put in place of the full URL
pass # We'll handle this specially
# Actually, the URL placeholders need to be restored from the original
# Let's just replace them with the actual URL patterns
# Each file may have different URLs, so we need to handle each case
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Skip lines that are just scope artifacts (should not appear as headers)
if stripped in ['**典型案例**', '**目录**', '**/** **/**']:
i += 1
continue
# Handle "## **典型案例**" -> ## {actual first case name}
if stripped == '## **典型案例**':
# Look at next non-empty line for the case name
j = i + 1
while j < len(lines) and not lines[j].strip():
j += 1
if j < len(lines):
next_stripped = lines[j].strip()
# Check if next line is a case name (should start with 涉, 侵害, etc.)
if next_stripped and any(next_stripped.startswith(kw) for kw in ['涉', '侵害', '确认', '假冒', '走秀', '误导', 'AI', '人工智能', '卡牌', '滑雪']):
result.append(f'\n## {next_stripped}\n')
i = j + 1
continue
elif next_stripped.startswith('**'):
# Section header like **案情摘要**, skip
i += 1
continue
# Handle case names (plain text lines that are case titles)
# These appear after "典型意义" or at the start, as plain text
# Common patterns: 侵害XXX案, 涉XXX案, 确认XXX案, etc.
is_case_name = False
if stripped and not stripped.startswith('#'):
# Check if this looks like a case name
case_name_patterns = [
r'^侵害["""].+?["""]?案',
r'^涉.+?案',
r'^确认.+?案',
r'^假冒.+?案',
r'^走秀.+?案',
r'^误导.+?案',
r'^AI.+?案',
r'^人工智能.+?案',
r'^卡牌.+?案',
r'^在先权益.+?案',
]
for pat in case_name_patterns:
if re.match(pat, stripped):
is_case_name = True
break
if is_case_name:
# Check if this case name already follows a ## header (don't double-add)
if result and result[-1].strip().startswith('## '):
# Already has a ## header
result.append(line)
else:
result.append(f'## {stripped}\n')
i += 1
continue
# Handle lines that are just metadata/case titles in wrong format
# Like "涉网络聚合支付平台数据权益著作权侵权及不正当竞争纠纷案"
# These should be converted to ## when they appear as standalone lines
# Check if previous line was a section header (meaning this is a case name)
if (stripped and not stripped.startswith('#') and
i > 0 and lines[i-1].strip() in ['### 典型意义', '### 裁判结果', '### 案情摘要', '### 基本案情']):
# This is a case name after a section - add ## header
result.append(f'## {stripped}\n')
i += 1
continue
# Skip URL placeholder lines (will be restored below)
if '__URL_PLACEHOLDER_' in stripped:
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
# Clean excessive blank lines
output = re.sub(r'\n{3,}', '\n\n', output)
# Remove trailing blank lines
output = output.rstrip() + '\n'
with open(filepath, 'w', encoding='utf-8') as f:
f.write(output)
print(f"Final fixed: {filepath}")
def main():
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
'20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
]
for f in files:
try:
final_fix(base + f)
except Exception as e:
print(f"Error: {f}: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Fix case headers across all 9 formatted files.
Main fix: "##\n**Case Name**" -> "## Case Name"
"""
import re
def fix_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
n = len(lines)
while i < n:
line = lines[i]
stripped = line.strip()
# Pattern: "##" or "## " on its own line, followed by bold case name
if stripped == '##' or stripped == '##':
if i + 1 < n:
next_stripped = lines[i + 1].strip()
# Check if next line is **Case Name** (bold)
if next_stripped.startswith('**') and next_stripped.endswith('**'):
case_name = next_stripped[2:-2].strip()
if case_name:
result.append(f'## {case_name}')
i += 2
continue
# Check if next line is a plain case name (starts with known prefix)
elif next_stripped:
prefixes = ['侵害', '涉', '确认', '假冒', '走秀', '误导', 'AI', '人工智能',
'卡牌', '在先权益', '恶意', '某种', '某移动', '某实业', '某科技',
'某酒店', '某生物', '杜某', '某化', '某网络', '某文化', '某传媒',
'某钢', '某化', '某制', '某光', '某医药', '某服装', '某电器']
for prefix in prefixes:
if next_stripped.startswith(prefix):
result.append(f'## {next_stripped}')
i += 2
continue
# It was a standalone ## with nothing meaningful after
result.append(line)
i += 1
continue
# Remove scope artifacts
skip_patterns = ['**/**', '/** **/**', '**/** **/**', '/**/', '**/**',
'**/** **/**', '**典型案例**', '**目录**', '/** 案例']
if stripped in skip_patterns:
i += 1
continue
# Handle lines that are just bold markers
if stripped in ['/**', '**/', '/**', '**']:
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
# Clean excessive blank lines
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w', encoding='utf-8') as f:
f.write(output)
def main():
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
'20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
]
for f in files:
try:
fix_file(base + f)
print(f"Fixed: {f}")
except Exception as e:
print(f"Error: {f}: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""Fix ## followed by blank lines then **Case Name** -> ## Case Name"""
import re
def find_next_nonempty(lines, start, max_look=5):
"""Find index of next non-empty line starting from start."""
for j in range(start, min(start + max_look, len(lines))):
if lines[j].strip():
return j
return None
def fix_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
n = len(lines)
while i < n:
line = lines[i]
stripped = line.strip()
# Check if this is a ## header line (possibly with trailing space)
if stripped == '##' or stripped == '## ' or stripped == '##':
# Find next non-empty line(s) after this
j = find_next_nonempty(lines, i + 1)
if j is not None:
next_stripped = lines[j].strip()
# Check if it's a bold case name **Case Name**
if next_stripped.startswith('**') and next_stripped.endswith('**'):
case_name = next_stripped[2:-2].strip()
if case_name:
result.append(f'## {case_name}')
i = j + 1 # Skip past this case name line
continue
# Check if it's a plain case name (starts with known prefix)
elif next_stripped and next_stripped.endswith('案'):
prefixes = ['侵害', '涉', '确认', '假冒', '走秀', '误导', 'AI', '人工智能',
'卡牌', '在先权益', '恶意', '某种', '某移动', '某实业', '某科技',
'某酒店', '某生物', '杜某', '某化', '某网络', '某文化', '某传媒',
'某钢', '某制', '某光', '某医药', '某服装', '某电器', '某机械',
'许可合同', '技术', '员工', '专利', '软件', '商标', '著作权']
for prefix in prefixes:
if next_stripped.startswith(prefix):
result.append(f'## {next_stripped}')
i = j + 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
# Clean excessive blank lines
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w', encoding='utf-8') as f:
f.write(output)
def main():
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
'20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
]
for f in files:
try:
fix_file(base + f)
print(f"Fixed: {f}")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""Fix Nanjing file - convert the comment-format case names to proper ## headers."""
import re
filepath = '/Users/maoking/.openclaw/skills/legal-text-format/archive/20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md'
with open(filepath) as f:
lines = f.readlines()
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Pattern: "# **CaseName**" followed by "# ——FullCaseName" or "# FullDescription"
if stripped.startswith('# **') and not stripped.startswith('###'):
# Extract case name from the bold section
# Try to combine with next line(s) that are also comment-style
case_name_parts = []
if '**' in stripped:
# Extract text between ** **
m = re.search(r'\*\*([^*]+)\*\*', stripped)
if m:
case_name_parts.append(m.group(1).strip())
# Check next lines for continuation (the "——" line)
j = i + 1
while j < min(i + 3, len(lines)):
next_stripped = lines[j].strip()
if next_stripped.startswith('# ——'):
# Full case name with parties
full = next_stripped[5:].strip() # Remove '# ——'
case_name_parts.append(full)
j += 1
break
elif next_stripped.startswith('# ') and not next_stripped.startswith('###'):
case_name_parts.append(next_stripped[2:].strip())
j += 1
break
elif next_stripped.startswith('#'):
break
else:
break
if case_name_parts:
full_name = ' '.join(case_name_parts)
result.append(f'## {full_name}\n')
i = j
continue
result.append(line)
i += 1
output = ''.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
print("Fixed Nanjing case headers")
# Verify
with open(filepath) as f:
content = f.read()
headers = re.findall(r'^## (.+)$', content, re.MULTILINE)
print(f"Total ## headers: {len(headers)}/10")
for h in headers:
print(f" ## {h[:70]}")
#!/usr/bin/env python3
"""Targeted fixes for remaining problematic files."""
import re
def fix_shanghai(filepath):
"""Fix Shanghai trade secrets file."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Fix: ## *案例目录** -> remove this line entirely
if stripped == '## *案例目录**' or stripped == '## **案例目录**':
i += 1
continue
# Fix: ## 案情摘要 -> ### 案情摘要
if stripped in ['## 案情摘要', '## 案情摘要']:
result.append('### 案情摘要')
i += 1
continue
# Fix: ## 裁判结果 -> ### 裁判结果
if stripped in ['## 裁判结果', '## 裁判结果']:
result.append('### 裁判结果')
i += 1
continue
# Fix: ## 典型意义 -> ### 典型意义
if stripped in ['## 典型意义', '## 典型意义']:
result.append('### 典型意义')
i += 1
continue
# Fix: ## ****专利代理师...**** -> ## 专利代理师...
if stripped.startswith('## ****') and stripped.endswith('****'):
case_name = stripped[6:-4].strip()
result.append(f'## {case_name}')
i += 1
continue
# Fix: ## 【基本案情】 etc -> ### 【基本案情】
if stripped.startswith('## 【') and stripped.endswith('】'):
result.append(stripped.replace('## ', '### '))
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_nanjing(filepath):
"""Fix Nanjing file."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Fix: ## ****专利代理师...**** -> ## 专利代理师擅自处分专利权属纠纷案
if stripped.startswith('## ****') and '****' in stripped[4:]:
# Extract case name from ****name****
inner = stripped[4:] # Remove '## '
if inner.startswith('****') and inner.endswith('****'):
case_name = inner[4:-4].strip()
result.append(f'## {case_name}')
i += 1
continue
# Fix: case name lines like "**Case Name**" that should be ## Case Name
if stripped.startswith('**') and stripped.endswith('**'):
case_name = stripped[2:-2].strip()
# Check if it looks like a case name
if case_name and (case_name.endswith('案') or '【' in case_name):
if '【' in case_name:
result.append(f'### {case_name}')
else:
result.append(f'## {case_name}')
i += 1
continue
# Fix: ## 【案件索引】 or ## 【基本案情】 etc -> ###
if stripped.startswith('## 【') and ('】' in stripped):
result.append(stripped.replace('## ', '### '))
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_jiangsu(filepath):
"""Fix Jiangsu file - extract case names from 案例X pattern."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Fix: case lines starting with 案例X、 or 案例X——
m = re.match(r'^案例(\d+)[、、、](.+)', stripped)
if m:
case_num = m.group(1)
rest = m.group(2).strip()
# Extract case name after —— if present, else use full rest
if '——' in rest:
# Get the part after ——
case_name = rest.split('——')[-1].strip()
else:
case_name = rest.strip()
result.append(f'## {case_name}')
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_shanghai_white_paper(filepath):
"""Fix Shanghai white paper file."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Remove scope artifacts
if stripped in ['**/**', '/** **/**', '**/** **/**', '/**/', '**/**',
'**/** **/**', '**典型案例**', '**目录**', '/** 案例',
'**/**', '**/', '/**']:
i += 1
continue
# Fix: ## ****xxx**** -> ## xxx
if stripped.startswith('## ****') and '****' in stripped[4:]:
inner = stripped[4:]
if inner.startswith('****') and inner.endswith('****'):
case_name = inner[4:-4].strip()
result.append(f'## {case_name}')
i += 1
continue
# Fix: ## 【xxx】 -> ### 【xxx】
if stripped.startswith('## 【') and '】' in stripped:
result.append(stripped.replace('## ', '### '))
i += 1
continue
# Fix: case name bold lines -> ## case name
if stripped.startswith('**') and stripped.endswith('**'):
case_name = stripped[2:-2].strip()
if case_name and case_name.endswith('案') and len(case_name) > 5:
result.append(f'## {case_name}')
i += 1
continue
elif case_name and '【' in case_name:
result.append(f'### {case_name}')
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_shanghai_main(filepath):
"""Fix Shanghai main file - ensure 14 case headers."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Handle remaining case names without ##
if (stripped and
not stripped.startswith('#') and
not stripped.startswith('**') and
stripped.endswith('案') and
5 < len(stripped) < 120):
prefixes = ['侵害', '涉', '确认', '假冒', '走秀', '误导', 'AI', '人工智能',
'卡牌', '在先权益', '恶意', '爬取', 'B服', '供热', '改编',
'虚构', '传播', '反向', '某种', '某移动', '某实业', '某科技',
'某酒店', '某生物', '杜某', '某化', '某网络', '某文化', '某传媒']
for prefix in prefixes:
if stripped.startswith(prefix):
# Check if prev line is already a ## header
if result and result[-1].strip().startswith('## '):
pass # Already has header
else:
result.append(f'## {stripped}')
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
# Run fixes
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
fix_shanghai(base + '20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md')
print("Fixed Shanghai trade secrets")
fix_nanjing(base + '20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md')
print("Fixed Nanjing")
fix_jiangsu(base + '20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md')
print("Fixed Jiangsu")
fix_shanghai_white_paper(base + '20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md')
print("Fixed Shanghai white paper")
fix_shanghai_main(base + '20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md')
print("Fixed Shanghai main")
#!/usr/bin/env python3
"""Targeted fixes for remaining problem files - more careful approach."""
import re
def fix_shanghai_ts(filepath):
"""Fix Shanghai trade secrets: add ## to case names, fix section headers."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Case names in bold: **Case Name** (standalone or with subtitle on next line)
if stripped.startswith('**') and stripped.endswith('**'):
inner = stripped[2:-2].strip()
if '【' in inner:
# Section header like **【基本案情】** -> ### 【基本案情】
result.append(f'### {inner}')
i += 1
continue
elif inner.endswith('案') and len(inner) > 4:
# Case name like **涉红外遥控技术秘密侵权纠纷案** -> ##
result.append(f'## {inner}')
i += 1
continue
elif '——' in inner or '"' in inner:
# Split case name, check next line
if i + 1 < len(lines):
next_line = lines[i + 1].strip()
if next_line.startswith('**') and next_line.endswith('**'):
# Combine with next bold line
next_inner = next_line[2:-2].strip()
full_name = f"{inner}——{next_inner}"
result.append(f'## {full_name}')
i += 2
continue
result.append(f'## {inner}')
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_nanjing(filepath):
"""Fix Nanjing: clean case headers, remove extra asterisks."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Fix: ## ****case name**** -> ## case name
if '****' in stripped and stripped.startswith('## '):
# Remove all **** occurrences
cleaned = stripped.replace('****', '').strip()
result.append(f'## {cleaned}')
i += 1
continue
# Fix: Bold case name lines
if stripped.startswith('**') and stripped.endswith('**'):
inner = stripped[2:-2].strip()
if inner.endswith('案') and len(inner) > 4:
result.append(f'## {inner}')
i += 1
continue
elif '【' in inner:
result.append(f'### {inner}')
i += 1
continue
# Fix: Split case name on multiple lines (like "# **寄生**" + "# **"生意参谋"**...")
if stripped.startswith('# **') or stripped.startswith('## **'):
if i + 1 < len(lines):
next_line = lines[i + 1].strip()
if next_line.startswith('**'):
# Combine lines
combined = stripped + next_line
combined_clean = combined.replace('# ', '').replace('## ', '').replace('****', '').replace('**', '').strip()
if combined_clean.endswith('案'):
result.append(f'## {combined_clean}')
i += 2
continue
result.append(line)
i += 1
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_white_paper(filepath):
"""Fix Shanghai white paper."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
for i, line in enumerate(lines):
stripped = line.strip()
# Remove scope artifacts
skip_patterns = ['**/**', '/** **/**', '**/** **/**', '/**/',
'**/**', '**/** **/**', '**典型案例**', '**目录**',
'/** 案例', '/**', '**/']
if stripped in skip_patterns:
continue
# Fix: ## ****case**** -> ## case
if '****' in stripped and stripped.startswith('##'):
cleaned = stripped.replace('****', '').strip()
result.append(cleaned)
continue
# Fix: bold case names
if stripped.startswith('**') and stripped.endswith('**'):
inner = stripped[2:-2].strip()
if inner.endswith('案') and len(inner) > 4:
result.append(f'## {inner}')
continue
elif '【' in inner:
result.append(f'### {inner}')
continue
# Fix: bold headers like **【案件索引】**
if stripped.startswith('**') and '【' in stripped and '】' in stripped:
inner = stripped[2:-2].strip()
result.append(f'### {inner}')
continue
result.append(line)
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
def fix_shanghai_main(filepath):
"""Fix Shanghai main - add missing ## to any remaining plain text case names."""
with open(filepath, 'r') as f:
content = f.read()
lines = content.split('\n')
result = []
for i, line in enumerate(lines):
stripped = line.strip()
# Check if this is a case name without ##
if (stripped and
not stripped.startswith('#') and
not stripped.startswith('**') and
stripped.endswith('案') and
5 < len(stripped) < 120):
prefixes = ['侵害', '涉', '确认', '假冒', '走秀', '误导', 'AI', '人工智能',
'卡牌', '在先权益', '恶意', '爬取', 'B服', '供热', '改编',
'虚构', '传播', '反向', '某种', '某移动', '某实业', '某科技',
'某酒店', '某生物', '杜某', '某化', '某网络', '某文化', '某传媒',
'某钢', '某制', '某光', '某医药', '某服装', '某电器', '某机械']
is_case = any(stripped.startswith(p) for p in prefixes)
if is_case:
# Check if previous added line is already a ## header for this
if result and result[-1].strip().startswith('## '):
pass # Already has header
else:
result.append(f'## {stripped}')
continue
result.append(line)
output = '\n'.join(result)
output = re.sub(r'\n{3,}', '\n\n', output)
output = output.rstrip() + '\n'
with open(filepath, 'w') as f:
f.write(output)
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
fix_shanghai_ts(base + '20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md')
print("Fixed Shanghai trade secrets")
fix_nanjing(base + '20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md')
print("Fixed Nanjing")
fix_white_paper(base + '20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md')
print("Fixed Shanghai white paper")
fix_shanghai_main(base + '20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md')
print("Fixed Shanghai main")
#!/usr/bin/env python3
"""
Format legal case compilation files according to legal-text-format skill rules.
"""
import re
import sys
import os
def format_text(text, court_name, source_url, title, keep_from_marker=None):
"""
Format legal text according to skill rules:
- Convert English punctuation to Chinese
- Add ## for case titles, ### for case sections
- Clean up excessive blank lines (max 1 consecutive)
- Convert numbers to half-width
- Remove content scope (intro/QR codes/promotion)
- Keep case content intro paragraph
"""
# Find where actual cases start (look for first case marker)
# Cases typically start with patterns like "案例1", "案例一", "/** 案例", etc.
# If keep_from_marker specified, start from there
if keep_from_marker:
idx = text.find(keep_from_marker)
if idx != -1:
text = text[idx:]
# Remove top matter (frontmatter, headers with source info, etc.)
# Keep the first meaningful paragraph about the announcement
# Find first case indicator
case_patterns = [
r'案例\s*\d+', # 案例1, 案例 1
r'案例一', r'案例二', r'案例三',
r'/\*\*/\s*案例', # /** 案例 **/
r'^\d+、', # 1、 at line start
r'^\[案例', # [案例
]
first_case_pos = len(text)
for pattern in case_patterns:
matches = list(re.finditer(pattern, text, re.MULTILINE))
if matches:
# Find earliest match that's likely a case header (not in middle of text)
for m in matches:
# Check if this looks like a case header (line start, or has context)
start_line = text[:m.start()].count('\n')
# Get the line containing this match
line_start = text.rfind('\n', 0, m.start()) + 1
line_end = text.find('\n', m.start())
line = text[line_start:line_end].strip()
if line.startswith(('案例', '/**', '[案例', '1、', '2、', '3、')) or \
re.match(r'案例\s*\d+', line):
if m.start() < first_case_pos:
first_case_pos = m.start()
break
# Also look for case names like "涉...案" or "XXX与XXX...案"
case_name_pattern = r'(?:涉|侵害|侵害|假冒|确认|某.*与某.*)\S{0,30}?(?:纠纷案|侵权案|不正当竞争案|发明专利侵权案|实用新型专利侵权案|外观设计专利侵权案)'
name_matches = list(re.finditer(case_name_pattern, text))
for m in name_matches:
# Check context - should be near start
if m.start() < first_case_pos and m.start() < 5000:
# Verify it's a case header (preceded by newlines)
before = text[max(0, m.start()-100):m.start()]
if '\n\n' in before or before.strip() == '':
first_case_pos = m.start()
break
# Find intro paragraph (e.g., "4月23日...")
intro_marker = None
for marker in ['4月23日', '4月24日', '4月22日']:
idx = text.find(marker)
if idx != -1 and idx < first_case_pos:
intro_marker = marker
# Find start of that line
line_start = text.rfind('\n', 0, idx) + 1
intro_marker = text[line_start:idx]
first_case_pos = line_start
break
if first_case_pos == len(text):
first_case_pos = 0
text = text[first_case_pos:]
# Now find where cases END (before footer "来源", QR codes, etc.)
end_patterns = [
r'来源\s*[::]\s*上海市高级人民法院',
r'来源\s*[::]\s*天津高院',
r'来源\s*[::]\s*青岛中院',
r'来源\s*[::]\s*湖南高院',
r'来源\s*[::]\s*宁波中院',
r'来源\s*[::]\s*江苏高院',
r'来源\s*[::]\s*南京中院',
r'扫码获取',
r'查看.*专题',
r'浏览知产财经',
r'联系我们',
r'知产财经官网',
r'^\s*END\s*$',
]
last_case_pos = len(text)
for pattern in end_patterns:
matches = list(re.finditer(pattern, text, re.IGNORECASE))
if matches:
for m in matches:
if m.start() < last_case_pos:
# Go back to find a good break point
last_case_pos = m.start()
# Find a good paragraph break before the footer
for i in range(last_case_pos, max(0, last_case_pos - 2000), -1):
if text[i] == '\n' and text[i-1] == '\n':
# Check if we're in a case section or footer
snippet = text[max(0, i-200):i]
if not re.search(r'典型意义|裁判结果|案情摘要|基本案情|裁判内容', snippet):
last_case_pos = i
break
# If we are in a case section, keep going back to find end of that section
if re.search(r'典型意义', snippet):
# Find end of this case
end_match = re.search(r'(?:▴|典型意义)', text[i:])
if end_match:
last_case_pos = i + end_match.end()
break
# Find the actual last "典型意义" section
all_meanings = list(re.finditer(r'典型意义', text))
if all_meanings:
last_meaning = all_meanings[-1]
# Find end of that section
end_search = text[last_meaning.end():last_meaning.end()+500]
# Find next case or footer
next_case = re.search(r'(?:/**|案例\s*\d+|案例[一二三四五六七八九十]+|来源|扫码|END)', end_search)
if next_case:
last_case_pos = last_meaning.end() + next_case.start()
else:
last_case_pos = last_meaning.end() + 300
text = text[:last_case_pos]
# Convert English punctuation to Chinese
replacements = [
(r'\(', '('), (r'\)', ')'),
(r',', ','), (r'\.', '。'), (r':', ':'), (r';', ';'),
(r'!', '!'), (r'\?', '?'),
(r'"', '"'), (r'"', '"'),
(r'''\ '''', '''‘'), (r'''\ ''', '''’'),
]
for pattern, repl in replacements:
text = re.sub(pattern, repl, text)
# Convert numbers to half-width (already mostly half-width, but ensure)
# Full-width digits: 0123456789 -> 0123456789
fw_digits = '0123456789'
hw_digits = '0123456789'
for i, fd in enumerate(fw_digits):
text = text.replace(fd, hw_digits[i])
# Clean up excessive blank lines (max 1 consecutive)
text = re.sub(r'\n{3,}', '\n\n', text)
# Remove image/QR code references that are just placeholders
text = re.sub(r'!\[.*?\]\(.*?(?:qr|QR|二维码|扫码).*?\)', '', text)
# Build output with metadata header
output = f"""# {title}
- **来源**:{court_name}
- **原文**:[点击查看]({source_url})
"""
# Process case structure
lines = text.split('\n')
result_lines = []
i = 0
in_case = False
in_section = False
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Skip obviously promotional/footer content
if any(kw in stripped for kw in ['扫码获取', '知产财经', '联系我们', '订阅我们', '点分享', '点收藏', '点在看', '点点赞', '浏览知产财经', '查看.*专题', '往期热文', '文章原文']):
i += 1
continue
# Case title detection - various formats
is_case_title = False
# Pattern: /** 案例1 **/ or /** 案例 **/
if re.match(r'/\*\*\s*案例', stripped) or re.match(r'\*\*\s*案例', stripped):
# Clean up and add as case header
case_name = re.sub(r'/\*\*|\*\*|案例\s*\d+\s*[/\*]*|/', '', stripped).strip()
result_lines.append(f'\n## {case_name}\n')
is_case_title = True
# Pattern: "案例1" or "案例一" as standalone
elif re.match(r'^案例[一二三四五六七八九十\d]+$', stripped):
# Look ahead for the actual case name
if i + 1 < len(lines):
next_line = lines[i + 1].strip()
if next_line and not next_line.startswith('#'):
result_lines.append(f'\n## {next_line}\n')
i += 1
is_case_title = True
else:
result_lines.append(f'\n## {stripped}\n')
is_case_title = True
# Pattern: Case name like "涉...案" or "XXX案" at section level
elif re.match(r'^涉\S+案$', stripped) or \
re.match(r'^[某\d]*(?:与|诉|等)[某\d\S]+案$', stripped) or \
re.match(r'^[A-Za-z0-9某]+[与诉等][A-Za-z0-9某]+案$', stripped):
# Check if this is a new case header
if i > 0:
prev = lines[i-1].strip()
if prev == '' or prev.startswith('##') or '裁判结果' in prev or '典型意义' in prev:
result_lines.append(f'\n## {stripped}\n')
is_case_title = True
# Pattern: numbered case like "1." or "一、" at start
elif re.match(r'^\d+[.、]', stripped) or re.match(r'^[一二三四五六七八九十]+[.、]', stripped):
# Clean up and add
case_name = re.sub(r'^\d+[.、]\s*', '', stripped)
if case_name and len(case_name) > 2:
result_lines.append(f'\n## {case_name}\n')
is_case_title = True
# Section headers (案情摘要, 裁判结果, 典型意义, 基本案情, etc.)
elif stripped in ['案情摘要', '基本案情', '裁判结果', '典型意义', '裁判内容', '【案情摘要】', '【基本案情】', '【裁判结果】', '【典型意义】', '【裁判内容】']:
section_name = re.sub(r'【|】', '', stripped)
result_lines.append(f'\n### {section_name}\n')
# Clean up remaining markdown artifacts
elif stripped.startswith('**') and stripped.endswith('**') and not is_case_title:
# Bold text that might be a header
inner = stripped.strip('*')
if len(inner) < 50 and not any(c in inner for c in ['。', ',', ';']):
result_lines.append(f'### {inner}\n')
else:
result_lines.append(line)
# Skip page navigation markers
elif '▴ 向上滑动查看更多 ▴' in stripped or '▴' in stripped:
i += 1
continue
# Skip lines that are just decorative
elif re.match(r'^[*\s\-—–|]+$', stripped):
i += 1
continue
# Skip image tags
elif stripped.startswith(':
i += 1
continue
# Skip lines with just source attribution
elif re.match(r'^来源\s*[::]', stripped):
i += 1
continue
# Skip "来源:|上海市高级人民法院" style lines
elif re.match(r'^\s*来源\s*\|?\s*上海', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*天津', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*青岛', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*湖南', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*宁波', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*江苏', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*南京', stripped):
i += 1
continue
elif re.match(r'^\s*来源\s*\|?\s*最高', stripped):
i += 1
continue
else:
result_lines.append(line)
i += 1
# Clean up excessive blank lines again
formatted_content = '\n'.join(result_lines)
formatted_content = re.sub(r'\n{3,}', '\n\n', formatted_content)
# Clean up lines that are just whitespace
lines = formatted_content.split('\n')
lines = [l for l in lines if l.strip() != '' or l == '']
# Remove trailing blank lines from content
while lines and lines[-1].strip() == '':
lines.pop()
formatted_content = '\n'.join(lines)
output += formatted_content
return output
if __name__ == '__main__':
if len(sys.argv) < 6:
print("Usage: format_legal_cases.py <input_file> <output_file> <court_name> <source_url> <title>")
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
court_name = sys.argv[3]
source_url = sys.argv[4]
title = sys.argv[5]
with open(input_file, 'r', encoding='utf-8') as f:
content = f.read()
# Extract just the body content (after the FreshRSS metadata block)
# Find where the actual content starts (after the --- frontmatter)
parts = content.split('---')
body_start = 0
for i, part in enumerate(parts):
if '4月' in part and ('日,' in part or '上午' in part or '下午' in part):
body_start = content.find(part)
break
else:
# Try to find first meaningful content
for marker in ['4月23日', '4月24日', '4月22日']:
idx = content.find(marker)
if idx != -1:
body_start = idx
break
body = content[body_start:]
# Remove trailing content
end_markers = ['---', '*由 FreshRSS', '*[由 FreshRSS']
for marker in end_markers:
idx = body.rfind(marker)
if idx > len(body) - 500:
body = body[:idx]
break
formatted = format_text(body, court_name, source_url, title)
os.makedirs(os.path.dirname(output_file), exist_ok=True)
with open(output_file, 'w', encoding='utf-8') as f:
f.write(formatted)
print(f"Formatted: {output_file}")
#!/usr/bin/env python3
"""
Step 2 formatter v2 - precise legal text formatting.
Handles punctuation carefully (not inside URLs/markdown), proper header structure.
"""
import re
import os
def smart_punct_replace(text):
"""
Convert English punctuation to Chinese, but be smart about it:
- Don't replace inside URLs (http://, https://)
- Don't replace inside markdown links [text](url)
- Don't replace inside image syntax 
- Don't replace inside code blocks
"""
# Protect URLs first by temporarily replacing with placeholders
urls = []
def protect_url(m):
urls.append(m.group(0))
return f'__URL_PLACEHOLDER_{len(urls)-1}__'
text = re.sub(r'https?://[^\s\'\")\)\]]+', protect_url, text)
# Protect markdown links [text](url)
md_links = []
def protect_md_link(m):
md_links.append(m.group(0))
return f'__MDLINK_PLACEHOLDER_{len(md_links)-1}__'
text = re.sub(r'\[([^\]]*)\]\(([^)]+)\)', protect_md_link, text)
# Protect image syntax too
md_images = []
def protect_md_image(m):
md_images.append(m.group(0))
return f'__MDIMAGE_PLACEHOLDER_{len(md_images)-1}__'
text = re.sub(r'!\[[^\]]*\]\([^)]+\)', protect_md_image, text)
# Now safe to replace punctuation (only in text, not in placeholders)
punct_map = [
(r'\(', '('), (r'\)', ')'),
(r',', ','), (r'\.', '。'), (r':', ':'), (r';', ';'),
(r'!', '!'), (r'\?', '?'),
]
for pattern, repl in punct_map:
text = re.sub(pattern, repl, text)
# Restore URLs
for i, url in enumerate(urls):
text = text.replace(f'__URL_PLACEHOLDER_{i}__', url)
# Restore markdown links (keep as-is, punctuation already converted)
for i, link in enumerate(md_links):
text = text.replace(f'__MDLINK_PLACEHOLDER_{i}__', link)
# Restore markdown images
for i, img in enumerate(md_images):
text = text.replace(f'__MDIMAGE_PLACEHOLDER_{i}__', img)
return text
def process_file(input_path, output_path, court_name, source_url, title):
with open(input_path, 'r', encoding='utf-8') as f:
raw = f.read()
# Find body start - first "4月XX日" paragraph
body_start = 0
for marker in ['4月23日', '4月24日', '4月22日', '4月21日', '4月20日']:
idx = raw.find(marker)
if idx != -1:
line_start = raw.rfind('\n', 0, idx) + 1
body_start = line_start
break
body = raw[body_start:]
# Find body end - look for last case's typical meaning section
# Find last "典型意义" position
last_meaning = body.rfind('典型意义')
if last_meaning > 0:
# Find the end of that section
tail_start = last_meaning
tail = body[tail_start:tail_start+2000]
# Look for next case pattern or footer
next_patterns = [
r'来源\s*[::]',
r'\n\s*扫码获取',
r'\n\s*浏览知产财经',
r'\n\s*联系我们',
r'\n\s*点分享',
r'\n\s*END\n',
]
cut_pos = len(body)
for pat in next_patterns:
m = re.search(pat, tail)
if m:
cut_pos = min(cut_pos, tail_start + m.start())
# If no clear footer, look for a natural break after last meaning
if cut_pos == len(body):
# Find a paragraph break after last meaning
snippet = body[last_meaning:last_meaning+1500]
# Find the last paragraph end
paras = re.findall(r'.+?(?=\n\n)', snippet, re.DOTALL)
if paras:
last_para_end = last_meaning
for p in paras:
last_para_end = body.find(p, last_meaning) + len(p)
cut_pos = last_para_end
body = body[:cut_pos]
# Remove trailing promotional sections more aggressively
for footer_kw in ['来源', '扫码', '知产财经', '联系我们', '订阅我们', '点分享', '点收藏', '点在看', '点点赞', 'END', '往期热文', '文章原文']:
# Find last occurrence
last_pos = 0
for m in re.finditer(re.escape(footer_kw), body):
# Check if this is in a meaningful context (not case content)
before = body[max(0, m.start()-200):m.start()]
if any(kw in before for kw in ['典型意义', '裁判结果', '案情摘要', '基本案情']):
continue # This is within case content
last_pos = m.start()
if last_pos > 0:
body = body[:last_pos]
# Apply punctuation conversion (smart)
body = smart_punct_replace(body)
# Now format headers
lines = body.split('\n')
result_lines = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Skip empty lines at start
if not stripped and i < 5:
i += 1
continue
# Skip obvious promotional/navigation lines
skip_patterns = [
r'^[\s]*data-sanitized-class',
r'^[\s]*$', # Will add back properly
r'^▴', # Navigation markers
r'^点分享',
r'^点收藏',
r'^点在看',
r'^点点赞',
r'^订阅我们',
r'^联系我们',
r'^知产财经',
r'^浏览知产财经',
r'^扫码获取',
r'^查看.*专题',
r'^往期热文',
r'^!\[\]\(http', # Broken image tags
r'^data-', # data attributes in text
]
if any(re.match(pat, stripped) for pat in skip_patterns):
i += 1
continue
# Skip lines that are just decorative
if re.match(r'^[_\-=*]{3,}$', stripped):
i += 1
continue
# Skip lines that look like HTML remnants
if stripped.startswith(' or stripped.startswith('!['):
i += 1
continue
# Skip lines that are just page indicators
if '向上滑动' in stripped or 'data-sanitized' in stripped:
i += 1
continue
# Process case title markers /** 案例X **/
if re.match(r'/\*\*\s*案例\s*\d+\s*\*/', stripped) or \
re.match(r'\*\*\s*案例\s*\d+\s*\*\*', stripped):
# Get next line for case name
case_name = ''
if i + 1 < len(lines):
next_line = lines[i + 1].strip()
if next_line and not next_line.startswith('#') and '案情' not in next_line and '裁判' not in next_line and '典型' not in next_line:
case_name = next_line
i += 1
else:
# Extract from current line
case_name = re.sub(r'/\*\*|\*\*|案例\s*\d+\s*[/\*]*', '', stripped).strip()
result_lines.append(f'\n## {case_name}\n')
i += 1
continue
# Process case title patterns like "案例1" on its own line
if re.match(r'^案例\s*\d+\s*[/因素]*$', stripped) or \
re.match(r'^案例[一二三四五六七八九十]+$', stripped):
result_lines.append(f'\n## [CASE_NAME_MISSING]\n')
i += 1
continue
# Process section headers in bold **案情摘要**, **裁判结果**, **典型意义**
if stripped.startswith('**') and stripped.endswith('**'):
inner = stripped.strip('*')
if inner in ['案情摘要', '基本案情', '裁判结果', '典型意义', '裁判内容', '入选理由及解读']:
result_lines.append(f'\n### {inner}\n')
i += 1
continue
# Process "【案情摘要】" style headers
if re.match(r'^【(案情摘要|基本案情|裁判结果|典型意义|裁判内容|入选理由及解读)】$', stripped):
inner = re.sub(r'【|】', '', stripped)
result_lines.append(f'\n### {inner}\n')
i += 1
continue
# Skip lines that are just sources e.g. "来源:上海市高级人民法院"
if re.match(r'^\s*来源\s*[::]\s*(上海|天津|青岛|湖南|宁波|江苏|南京|最高|北京|浙江|广东|山东|四川|重庆|湖北|河北|辽宁|福建|河南|[一二三四五六七八九十]+)', stripped):
i += 1
continue
# Skip "来源 |" lines
if re.match(r'^\s*来源\s*\|', stripped):
i += 1
continue
result_lines.append(line)
i += 1
body = '\n'.join(result_lines)
# Clean excessive blank lines
body = re.sub(r'\n{3,}', '\n\n', body)
# Convert bold markers that are case markers like **/** **案例1** **/
# Already handled above
# Remove lines that are just empty or whitespace at the very end
while body.endswith('\n'):
if body.endswith('\n\n\n'):
body = body[:-1]
else:
break
# Build final output
output = f"""# {title}
- **来源**:{court_name}
- **原文**:[点击查看]({source_url})
"""
output += body
# Final cleanup
output = re.sub(r'\n{3,}', '\n\n', output)
# Remove trailing blank lines
output = output.rstrip() + '\n'
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(output)
print(f"Written: {output_path}")
def main():
base_in = '/Users/maoking/Desktop/Clawd/05 - 📡 外部同步/法律法规/'
base_out = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
('260424 附判决┃上海高院发布2025年知识产权司法保护典型案例(15件).md',
'20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'上海市高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532175&idx=2&sn=751cc17ca602a741d0907998de151fbe&chksm=f87a9b84ec2b4bc7b78b84fdbd4bf0ba3827e3eb63f8f9768c93aa60618863f60309595d8d24&scene=0#rd',
'上海高院发布2025年知识产权司法保护典型案例(15件)'),
('260424 附判决┃天津高院发布2025年天津法院知识产权典型案例(7件).md',
'20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'天津市高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=3&sn=3a1b1ab7c375e156918800d365010de4&chksm=f8132c0da197ac9347ebc93310b701ec2fd60fc5d93cab64d9c641836e139c7845e97107bf74&scene=0#rd',
'天津高院发布2025年天津法院知识产权典型案例(7件)'),
('260424 附判决┃青岛中院发布2025年青岛法院知识产权司法保护典型案例(10件).md',
'20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'青岛市中级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532204&idx=2&sn=e220a7465591667168de8d685ce05a8d&chksm=f8c9e4c174bd94ae03bbd21779674c01f5dd9d3ab12a5f6c71180eeed91873fce2ee30b7991d&scene=0#rd',
'青岛中院发布2025年青岛法院知识产权司法保护典型案例(10件)'),
('260424 附判决┃湖南高院发布2025年知识产权司法保护状况及服务保障新质生产力发展典型案.md',
'20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'湖南省高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=2&sn=2e4e073bed6c1690a7ede674cb29aec1&chksm=f8b9319c5f542f0b4ca89b8532273823caefe2ec8cf57cae69a39fc78430733517fa3c2ae1bf&scene=0#rd',
'湖南高院发布2025年知识产权司法保护状况及服务保障新质生产力发展典型案例'),
('260424 附判决┃宁波中院发布2025年度宁波法院知识产权审判典型案例(10件).md',
'20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'宁波市中级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=4&sn=a017ba462c773185997706d6d1bd8d5d&chksm=f85c4b3d874dc4d44897ad3cce8fa702f91cb63ec37b2c324217fe6c6e31bd678a408b0926ec&scene=0#rd',
'宁波中院发布2025年度宁波法院知识产权审判典型案例(10件)'),
('260424 附判决┃江苏高院发布2025年服务保障科技创新和产业创新融合知产典型案例(10件.md',
'20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'江苏省高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=1&sn=69c92887995f2e2d071a934d59a2be7e&chksm=f86160cc32719cb2c3e6d6e564503e2e31c5f59fd13a61e0a25560cc685ed293645966e7be25&scene=0#rd',
'江苏高院发布2025年服务保障科技创新和产业创新融合知产典型案例(10件)'),
('260424 上海高院发布涉商业秘密保护典型案例(10件).md',
'20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'上海市高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532175&idx=1&sn=123ffe43ea091b75c2b3fb633a3e433a&chksm=f81826aa74c0128a9fac0c4918dd2db3b9ea0b6403074b909ee91f132735bd72f2f6813c5ef8&scene=0#rd',
'上海高院发布涉商业秘密保护典型案例(10件)'),
('260424 附判决┃南京中院发布2025年南京法院知识产权十大案例.md',
'20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'南京市中级人民法院',
'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532204&idx=1&sn=7127f2c0695db3e924509b24a0a2cb27&chksm=f87c7d06daaa5b24f5bc37b84f6fc30ec6c896dfa80a05772a9ad343096f36d00b81b29b5d8f&scene=0#rd',
'南京中院发布2025年南京法院知识产权十大案例'),
('260423 4·26特辑 _ 上海法院发布知识产权审判白皮书和典型案例.md',
'20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
'上海市高级人民法院',
'http://mp.weixin.qq.com/s?__biz=MjM5NzU5ODEzNw==&mid=2665453880&idx=1&sn=44354253167edd6ec8268facdae0adba&chksm=bcd59bf527ccf9d451cb566915572414243a1c12c9cfc2c49a785cc02bfca32061912c70a4fd&scene=0#rd',
'上海法院发布知识产权审判白皮书和典型案例'),
]
for f in files:
inp = base_in + f[0]
outp = base_out + f[1]
try:
process_file(inp, outp, f[2], f[3], f[4])
except Exception as e:
print(f"Error: {f[0]}: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Step 2 formatter for legal case compilation files.
Processes raw markdown files and outputs formatted versions.
"""
import re
import os
import json
def clean_text(text):
"""Clean and format text according to skill rules."""
# Remove image tags that are just URLs
text = re.sub(r'!\[.*?\]\(.*?\)', '', text)
# Convert English punctuation to Chinese
text = text.replace('(', '(').replace(')', ')')
text = text.replace(',', ',')
text = text.replace('.', '。')
text = text.replace(':', ':')
text = text.replace(';', ';')
text = text.replace('!', '!')
text = text.replace('?', '?')
# Full-width to half-width digits
fw = '0123456789'
hw = '0123456789'
for f, h in zip(fw, hw):
text = text.replace(f, h)
# Clean excessive blank lines
text = re.sub(r'\n{3,}', '\n\n', text)
return text
def process_file(input_path, output_path, court_name, source_url, title):
"""Process a single file."""
with open(input_path, 'r', encoding='utf-8') as f:
raw = f.read()
# Extract body - find the first content marker (4月XX日)
marker_found = False
for marker in ['4月23日', '4月24日', '4月22日', '4月21日', '4月20日']:
idx = raw.find(marker)
if idx != -1:
# Go back to start of that line
line_start = raw.rfind('\n', 0, idx) + 1
body = raw[line_start:]
marker_found = True
break
if not marker_found:
# Try to find start after frontmatter
parts = raw.split('---')
body = raw
for part in parts[1:]:
if any(m in part for m in ['4月', '案例', '案情', '裁判']):
body = raw[raw.find(part):]
break
# Remove trailing content (after last case)
# Find "来源" or "扫码" footer
footer_patterns = [
r'\n来源\s*[::]\s*',
r'\n\s*来源\s*[::]',
r'\n\s*扫码获取',
r'\n\s*浏览知产财经',
r'\n\s*联系我们',
r'\n\s*订阅我们',
r'\n\s*点分享',
r'\n\s*END\n',
r'\n\s*-\{3,\}\n', # --- separators
]
last_good = len(body)
for fp in footer_patterns:
matches = list(re.finditer(fp, body))
if matches:
for m in reversed(matches):
# Only cut if this looks like footer (near end)
if m.start() > len(body) * 0.7:
last_good = min(last_good, m.start())
break
body = body[:last_good]
# Find actual last case end
# Look for the last "典型意义" section
last_meaning = body.rfind('典型意义')
if last_meaning > 0:
# Find end of that section - look for next case or footer
tail = body[last_meaning:]
# Find good cut point - usually a paragraph break after the last meaning
meaning_end = last_meaning + 500
for i in range(last_meaning + 300, min(len(body), last_meaning + 1000)):
if body[i] == '\n' and body[i-1] == '\n':
# Check if we're past the last case content
snippet = body[i:i+100]
if any(kw in snippet for kw in ['来源', '扫码', '知产财经', '联系我们', 'END', '往期']):
meaning_end = i
break
elif i - last_meaning > 800:
meaning_end = i
break
body = body[:meaning_end]
body = clean_text(body)
# Build output
output = f"""# {title}
- **来源**:{court_name}
- **原文**:[点击查看]({source_url})
"""
output += body
# Final cleanup
output = re.sub(r'\n{3,}', '\n\n', output)
# Remove trailing blank lines
while output.endswith('\n\n'):
output = output[:-1]
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(output)
print(f"Written: {output_path}")
def main():
base_in = '/Users/maoking/Desktop/Clawd/05 - 📡 外部同步/法律法规/'
base_out = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
{
'in': '260424 附判决┃上海高院发布2025年知识产权司法保护典型案例(15件).md',
'out': '20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'court': '上海市高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532175&idx=2&sn=751cc17ca602a741d0907998de151fbe&chksm=f87a9b84ec2b4bc7b78b84fdbd4bf0ba3827e3eb63f8f9768c93aa60618863f60309595d8d24&scene=0#rd',
'title': '上海高院发布2025年知识产权司法保护典型案例(15件)',
},
{
'in': '260424 附判决┃天津高院发布2025年天津法院知识产权典型案例(7件).md',
'out': '20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'court': '天津市高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=3&sn=3a1b1ab7c375e156918800d365010de4&chksm=f8132c0da197ac9347ebc93310b701ec2fd60fc5d93cab64d9c641836e139c7845e97107bf74&scene=0#rd',
'title': '天津高院发布2025年天津法院知识产权典型案例(7件)',
},
{
'in': '260424 附判决┃青岛中院发布2025年青岛法院知识产权司法保护典型案例(10件).md',
'out': '20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'court': '青岛市中级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532204&idx=2&sn=e220a7465591667168de8d685ce05a8d&chksm=f8c9e4c174bd94ae03bbd21779674c01f5dd9d3ab12a5f6c71180eeed91873fce2ee30b7991d&scene=0#rd',
'title': '青岛中院发布2025年青岛法院知识产权司法保护典型案例(10件)',
},
{
'in': '260424 附判决┃湖南高院发布2025年知识产权司法保护状况及服务保障新质生产力发展典型案.md',
'out': '20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'court': '湖南省高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=2&sn=2e4e073bed6c1690a7ede674cb29aec1&chksm=f8b9319c5f542f0b4ca89b8532273823caefe2ec8cf57cae69a39fc78430733517fa3c2ae1bf&scene=0#rd',
'title': '湖南高院发布2025年知识产权司法保护状况及服务保障新质生产力发展典型案例',
},
{
'in': '260424 附判决┃宁波中院发布2025年度宁波法院知识产权审判典型案例(10件).md',
'out': '20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'court': '宁波市中级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=4&sn=a017ba462c773185997706d6d1bd8d5d&chksm=f85c4b3d874dc4d44897ad3cce8fa702f91cb63ec37b2c324217fe6c6e31bd678a408b0926ec&scene=0#rd',
'title': '宁波中院发布2025年度宁波法院知识产权审判典型案例(10件)',
},
{
'in': '260424 附判决┃江苏高院发布2025年服务保障科技创新和产业创新融合知产典型案例(10件.md',
'out': '20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'court': '江苏省高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532189&idx=1&sn=69c92887995f2e2d071a934d59a2be7e&chksm=f86160cc32719cb2c3e6d6e564503e2e31c5f59fd13a61e0a25560cc685ed293645966e7be25&scene=0#rd',
'title': '江苏高院发布2025年服务保障科技创新和产业创新融合知产典型案例(10件)',
},
{
'in': '260424 上海高院发布涉商业秘密保护典型案例(10件).md',
'out': '20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'court': '上海市高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532175&idx=1&sn=123ffe43ea091b75c2b3fb633a3e433a&chksm=f81826aa74c0128a9fac0c4918dd2db3b9ea0b6403074b909ee91f132735bd72f2f6813c5ef8&scene=0#rd',
'title': '上海高院发布涉商业秘密保护典型案例(10件)',
},
{
'in': '260424 附判决┃南京中院发布2025年南京法院知识产权十大案例.md',
'out': '20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'court': '南京市中级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MzUxMDAwNTI3OQ==&mid=2247532204&idx=1&sn=7127f2c0695db3e924509b24a0a2cb27&chksm=f87c7d06daaa5b24f5bc37b84f6fc30ec6c896dfa80a05772a9ad343096f36d00b81b29b5d8f&scene=0#rd',
'title': '南京中院发布2025年南京法院知识产权十大案例',
},
{
'in': '260423 4·26特辑 _ 上海法院发布知识产权审判白皮书和典型案例.md',
'out': '20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
'court': '上海市高级人民法院',
'url': 'http://mp.weixin.qq.com/s?__biz=MjM5NzU5ODEzNw==&mid=2665453880&idx=1&sn=44354253167edd6ec8268facdae0adba&chksm=bcd59bf527ccf9d451cb566915572414243a1c12c9cfc2c49a785cc02bfca32061912c70a4fd&scene=0#rd',
'title': '上海法院发布知识产权审判白皮书和典型案例',
},
]
for f in files:
inp = base_in + f['in']
outp = base_out + f['out']
try:
process_file(inp, outp, f['court'], f['url'], f['title'])
except Exception as e:
print(f"Error processing {f['in']}: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""Post-process formatted legal case files - clean up remaining formatting artifacts."""
import re
import os
def postprocess(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
result = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# Skip known artifact lines
skip_set = {
'**典型案例**', '**目录**', '**/** **/**',
}
# Skip bold scope artifacts
if stripped in skip_set:
i += 1
continue
# Skip case separators like " /** 案例1 **/ " or " **/** **案例1** **/** "
# Check for patterns containing "案例" in bold markers
if ('案例' in stripped and stripped.count('*') >= 2 and
all(c in stripped for c in ['/**', '**'])):
i += 1
continue
# Skip patterns like " /** **案例1** **/"
if re.match(r'^/\*\*\s*案例', stripped) or re.match(r'^\*\*\s*案例', stripped):
i += 1
continue
# Skip stray bold markers
if stripped in ('/**', '**/', '/**/', '**/**', '/** **/**'):
i += 1
continue
# Handle case separator /** 案例X **/ with case name on next line
if re.search(r'/\*\*.*案例.*\*\*/', stripped) or re.search(r'\*\*.*案例.*\*\*', stripped):
# Get case name from next line
if i + 1 < len(lines):
next_line = lines[i + 1].strip()
if next_line and not next_line.startswith('#'):
result.append(f'\n## {next_line}\n')
i += 2
continue
i += 1
continue
result.append(line)
i += 1
output = '\n'.join(result)
# Clean excessive blank lines
output = re.sub(r'\n{3,}', '\n\n', output)
# Remove trailing blank lines
output = output.rstrip() + '\n'
with open(filepath, 'w', encoding='utf-8') as f:
f.write(output)
print(f"Post-processed: {filepath}")
def main():
base = '/Users/maoking/.openclaw/skills/legal-text-format/archive/'
files = [
'20260425_120000_上海高院2025年知识产权司法保护典型案例/20260425_上海高院2025年知识产权司法保护典型案例_formatted.md',
'20260425_120001_天津高院2025年天津法院知识产权典型案例/20260425_天津高院2025年天津法院知识产权典型案例_formatted.md',
'20260425_120002_青岛中院2025年青岛法院知识产权司法保护典型案例/20260425_青岛中院2025年青岛法院知识产权司法保护典型案例_formatted.md',
'20260425_120003_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例/20260425_湖南高院2025年知识产权司法保护状况及服务保障新质生产力发展典型案例_formatted.md',
'20260425_120004_宁波中院2025年度宁波法院知识产权审判典型案例/20260425_宁波中院2025年度宁波法院知识产权审判典型案例_formatted.md',
'20260425_120005_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例/20260425_江苏高院2025年服务保障科技创新和产业创新融合知产典型案例_formatted.md',
'20260425_120006_上海高院涉商业秘密保护典型案例/20260425_上海高院涉商业秘密保护典型案例_formatted.md',
'20260425_120007_南京中院2025年南京法院知识产权十大案例/20260425_南京中院2025年南京法院知识产权十大案例_formatted.md',
'20260425_120008_上海法院知识产权审判白皮书和典型案例/20260425_上海法院知识产权审判白皮书和典型案例_formatted.md',
]
for f in files:
try:
postprocess(base + f)
except Exception as e:
print(f"Error: {f}: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()