<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>原创 &#8211; 编码无悔 /  Intent &amp; Focused</title>
	<atom:link href="https://www.codelast.com/category/original/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.codelast.com</link>
	<description>最优化之路</description>
	<lastBuildDate>Fri, 06 Nov 2026 12:38:49 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
	<item>
		<title>[原创] 在 Ubuntu 上更新「极点五笔」词库（fcitx4 码表）</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8-ubuntu-%e4%b8%8a%e6%9b%b4%e6%96%b0%e3%80%8c%e6%9e%81%e7%82%b9%e4%ba%94%e7%ac%94%e3%80%8d%e8%af%8d%e5%ba%93%ef%bc%88fcitx4-%e7%a0%81%e8%a1%a8%ef%bc%89/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8-ubuntu-%e4%b8%8a%e6%9b%b4%e6%96%b0%e3%80%8c%e6%9e%81%e7%82%b9%e4%ba%94%e7%ac%94%e3%80%8d%e8%af%8d%e5%ba%93%ef%bc%88fcitx4-%e7%a0%81%e8%a1%a8%ef%bc%89/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Fri, 06 Nov 2026 12:38:49 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fcitx4]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[更新词库]]></category>
		<category><![CDATA[极点五笔]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14278</guid>

					<description><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">现在使用五笔输入法的人是越来越少了，像我一样在Linux系统上使用五笔的，就更是少得可怜。想当年，五笔输入法还是一个比较流行的输入法的时候，在Windows上有一个非常火爆的软件：极点五笔输入法。后来有人把它移植到了Linux系统，但这种没有大公司支持的项目，是没有持续更新支持的，所以，这么多年来，我一直使用着一个过时的词库，如果遇到词库里没有的专用词，我就自己用快捷键把它加到词库里，多年累积下来，也算是更新了一小部分词库。但实际上，还是有很多覆盖不到的词，比如原始词库连&#34;支付宝&#34;都不认识。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">为了解决这个问题，我在AI的辅助下做了一些调研，并在此基础上对Ubuntu上使用的极点五笔输入法词库做了一次与时俱进的更新。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">说得简单点，就是如下这个过程：从公网找词库 &#8594; 筛选 &#8594; 转成 fcitx4 二进制码表 &#8594; 校验 &#8594; 上线 &#8594; 回滚预案。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">配套代码已开源：<a href="https://github.com/codelast/update-freewb-dict-on-linux" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);" target="_blank">LINK</a></strong></section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">文中只展示核心代码片段；<strong style="font-weight: bold; color: black;">片段为示意节选，与仓库里的文件不完全逐行一致，请以仓库中的实际代码为准</strong>（每节标注了文件名并附链接）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">以下所有命令都假设你已克隆并进入仓库目录：</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">git clone https://github.com/codelast/update-freewb-dict-on-linux.git &#38;&#38; cd update-freewb-dict-on-linux</code></section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">适用：fcitx 4.x + <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">fcitx-table-wbpy</code>（「五笔拼音」，词库源自极点五笔的极爽词库）。</section>
</li>
</ul>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span id="more-14278"></span><br />
	0. 速览</span></h2>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				环节</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				要点</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				我的Ubuntu机器在用的东西</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Linux 上没有 Windows 版极点五笔；实际是 <strong style="font-weight: bold;">fcitx4 的 table 引擎 + wbpy 码表</strong>，词库是「极爽词库 6.0」</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				词库文件</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>~/.config/fcitx/table/wbpy.mb</code></td></tr></tbody></table></section>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8-ubuntu-%e4%b8%8a%e6%9b%b4%e6%96%b0%e3%80%8c%e6%9e%81%e7%82%b9%e4%ba%94%e7%ac%94%e3%80%8d%e8%af%8d%e5%ba%93%ef%bc%88fcitx4-%e7%a0%81%e8%a1%a8%ef%bc%89/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;">
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">现在使用五笔输入法的人是越来越少了，像我一样在Linux系统上使用五笔的，就更是少得可怜。想当年，五笔输入法还是一个比较流行的输入法的时候，在Windows上有一个非常火爆的软件：极点五笔输入法。后来有人把它移植到了Linux系统，但这种没有大公司支持的项目，是没有持续更新支持的，所以，这么多年来，我一直使用着一个过时的词库，如果遇到词库里没有的专用词，我就自己用快捷键把它加到词库里，多年累积下来，也算是更新了一小部分词库。但实际上，还是有很多覆盖不到的词，比如原始词库连&quot;支付宝&quot;都不认识。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">为了解决这个问题，我在AI的辅助下做了一些调研，并在此基础上对Ubuntu上使用的极点五笔输入法词库做了一次与时俱进的更新。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">说得简单点，就是如下这个过程：从公网找词库 &rarr; 筛选 &rarr; 转成 fcitx4 二进制码表 &rarr; 校验 &rarr; 上线 &rarr; 回滚预案。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">配套代码已开源：<a href="https://github.com/codelast/update-freewb-dict-on-linux" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);" target="_blank">LINK</a></strong></section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">文中只展示核心代码片段；<strong style="font-weight: bold; color: black;">片段为示意节选，与仓库里的文件不完全逐行一致，请以仓库中的实际代码为准</strong>（每节标注了文件名并附链接）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">以下所有命令都假设你已克隆并进入仓库目录：</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">git clone https://github.com/codelast/update-freewb-dict-on-linux.git &amp;&amp; cd update-freewb-dict-on-linux</code></section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">适用：fcitx 4.x + <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">fcitx-table-wbpy</code>（「五笔拼音」，词库源自极点五笔的极爽词库）。</section>
</li>
</ul>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span id="more-14278"></span><br />
	0. 速览</span></h2>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				环节</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				要点</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				我的Ubuntu机器在用的东西</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Linux 上没有 Windows 版极点五笔；实际是 <strong style="font-weight: bold;">fcitx4 的 table 引擎 + wbpy 码表</strong>，词库是「极爽词库 6.0」</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				词库文件</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>~/.config/fcitx/table/wbpy.mb</code>（二进制，约 10MB，30 万条量级）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				能不能直接编辑</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">不能</strong>。私有二进制格式，必须解析&rarr;改&rarr;重新序列化</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				权威格式来源</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				fcitx4 源码 <code>src/im/table/tabledict.c</code>、<code>tools/cli/mb2txt.c</code>、<code>tools/cli/txt2mb.c</code></td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				关键工具</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				用 <code>build_mb2txt.sh</code> 编译<strong style="font-weight: bold;">官方</strong> <code>mb2txt</code> 做回读校验</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				上线流程</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				停 fcitx &rarr; 备份 &rarr; 基于最新文件重建 &rarr; 官方工具全量 diff &rarr; 替换 &rarr; 启动 &rarr; 实打验证</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				回滚</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>./rollback.sh &lt;备份&gt;</code>，一分钟</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	本次实际成果（示例）：词库 312,315 &rarr; 336,897 条，新增五笔 10,203 条、拼音 14,378 条，原有记录零丢失。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	仓库文件清单</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	下表文件均位于仓库 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">main</code> 分支，点击文件名可直达源码。</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				文件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				作用</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				依赖</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/build_mb2txt.sh" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>build_mb2txt.sh</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				编译官方 <code>mb2txt</code>（码表 &rarr; 文本）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				gcc、curl</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/tabledict.h" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>tabledict.h</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				编译用的极简头文件</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				&mdash;</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/stub.c" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>stub.c</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>fcitx_utils_read_uint32</code> 的替代实现</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				&mdash;</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/mb_table.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>mb_table.py</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">码表读写库</strong>（解析 / 序列化 / 有序插入）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				仅标准库</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/merge_wubi.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>merge_wubi.py</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				并入五笔词条（type=0）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				mb_table.py</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/gen_pinyin.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>gen_pinyin.py</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				生成拼音码（含多音备选）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				pypinyin</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/merge_pinyin.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>merge_pinyin.py</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				并入拼音记录（type=1）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				mb_table.py</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/filter_candidates.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>filter_candidates.py</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				候选筛选（差集 + 质量判据）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				词库文件、字频表</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/apply.sh" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>apply.sh</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				停服&rarr;备份&rarr;校验&rarr;替换&rarr;重启</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				mb2txt</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/rollback.sh" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code>rollback.sh</code></a></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				回滚到备份</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				&mdash;</td>
</tr>
</tbody>
</table>
</section>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">1. 背景与原理</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.1 「极点五笔」在 Linux 上到底是什么</span></h3>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				平台</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				实现</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				词库载体</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Windows</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				极点五笔（FreeWB，杜志民）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>freeime\mb\</code> 下的纯文本码表目录</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Ubuntu（本文）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				fcitx4 的 table 引擎 + 码表 <code>wbpy</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>~/.config/fcitx/table/wbpy.mb</code>（二进制）</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	所以「更新极点五笔词库」在 Linux 上等于「替换 wbpy.mb 里的词条数据」。<strong style="font-weight: bold;">引擎、快捷键、皮肤、用户造词习惯全部不变</strong>，只是数据变了。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">wbpy.conf</code> 里几个决定格式的关键参数：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">[CodeTable]
UniqueName=wbpy
Name[zh_CN]=五笔拼音
File=wbpy.mb
ExactMatch=False     ; 前缀匹配 &rarr; 拼音码被截断也照样能用
UsePY=False
PYKey=z
</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.2 为什么不直接用文本编辑器</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">.mb</code> 是 fcitx 私有的二进制表：头部含按键字符集、码长、组词规则，记录区是按码排序的定长头 + 变长词条。 用文本工具改，轻则加载失败，重则索引错乱（能启动但查不到词）。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	2. 二进制格式（权威来源 + 实测）</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.1 源码位置</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	GitHub <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">fcitx/fcitx</code>（fcitx4，已归档）：</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				文件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				作用</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>src/im/table/tabledict.c</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>TableData::load/save</code>，<strong style="font-weight: bold;">格式的唯一权威</strong></td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>tools/cli/mb2txt.c</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				官方 二进制 &rarr; 文本</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>tools/cli/txt2mb.c</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				官方 文本 &rarr; 二进制</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 不要参考 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">nopdan/rose</code> 的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">format/fcitx4_mb</code>：它假设码字段宽度 = <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">codeLen + 1</code>（=5），实际是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">pyCodeLen + 1</code>（本文示例 = 13）。按它的写法解析会整体错位一条记录。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.2 文件结构</span></h3>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">┌── 头部 ─────────────────────────────────────────────┐
│ u32  0                    新格式标志                  │
│ i8   version              3 = 当前版本（&lt;3 为旧版）   │
│ u32  keyLen                                          │
│ u8   KeyCode[keyLen+1]    NUL 结尾，如 <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;abc...y&quot;</span>      │
│ u8   codeLen              码长（本文示例 4）          │
│ u8   pyCodeLen            拼音码长（本文示例 12）     │
│ u32  ignoreLen                                       │
│ u8   InvalidChar[ignoreLen+1]                        │
│ u8   hasRule             1 = 后面跟组词规则表         │
│ (codeLen-1) &times; [ u8 flag, u8 words,                   │
│                 codeLen &times; (u8 flag, u8 <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">which</span>, u8 idx) ]│
│ u32  recordCount                                     │
├── 记录区（按码排序，共 recordCount 条）──────────────┤
│ 每条：                                               │
│   码    pyCodeLen+1 字节（NUL 填充；本文 13 字节）    │
│   u32   词长（**含**结尾 NUL）                        │
│   词    UTF-8 字节 + NUL                             │
│   i8    <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">type</span>  0=五笔 1=拼音 2=自造词 3=提示           │
│   u32   iHit  用户命中次数（新词写 0）                │
│   u32   iIndex 全局递增序号（新词取 max+1）           │
└─────────────────────────────────────────────────────┘
</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.3 三条硬约束（踩过才知道）</span></h3>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">记录必须按「码的首字符」分组排序</strong>。<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">table.c</code>（上游源码，仅阅读参考） 建索引时只比较 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">cChar != strCode[0]</code>，顺序乱了就查不到。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">同码候选的先后 = 记录在文件里的先后</strong>。想让它排最后，就插到该码组的<strong style="font-weight: bold; color: black;">末尾</strong>；想排第一，插到组首。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">前 4 字节不是词长</strong>，而是码字段的第 5~8 字节。这是最容易搞错的地方（第一版解析器就栽在这）。</section>
</li>
</ol>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.4 匹配行为（决定拼音码能不能截断）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">tabledict.c::TableCompareCode()</code> 只按<strong style="font-weight: bold;">用户输入长度</strong>逐字节比较，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">wbpy.conf</code> 里 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ExactMatch=False</code>，所以是<strong style="font-weight: bold;">前缀匹配</strong>：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">size_t</span> tmp_len = <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">strlen</span>(strUser);
<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> (i = <span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>; i &lt; tmp_len; i++) { <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> (strUser[i] != strDict[i]) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> &hellip;; }
<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> (exactMatch &amp;&amp; <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">strlen</span>(strUser) != <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">strlen</span>(strDict)) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-number" style="color: #986801; line-height: 26px;">-999</span>;
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	含义：拼音码被截断到 12 字母也照样能用（打前几个字母就出候选）；五笔 4 码同理。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	3. 工具链：编译官方 mb2txt</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">文件：<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/build_mb2txt.sh" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">build_mb2txt.sh</code></a></strong>（配合 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/tabledict.h" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">tabledict.h</code></a>、<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/stub.c" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">stub.c</code></a>）</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">mb2txt.c</code>（脚本自动下载） 只外部依赖一个 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">fcitx_utils_read_uint32</code>，所以可以脱离 fcitx 开发环境单独编译。脚本做的事就是：放好极简头文件 &rarr; 下载官方 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">mb2txt.c</code> &rarr; 用 stub 编译。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	核心三行：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">mkdir -p im/table &amp;&amp; cp -f tabledict.h im/table/tabledict.h
curl -fsSL -o mb2txt.c https://raw.githubusercontent.com/fcitx/fcitx/master/tools/cli/mb2txt.c
gcc -O2 -I. -o mb2txt mb2txt.c stub.c
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	产出用法：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">./mb2txt        ~/.config/fcitx/table/wbpy.mb &gt; table.txt   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 二进制 &rarr; 文本</span>
./mb2txt -o 旧版.mb &gt; old.txt                               <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 旧格式（version&lt;3）</span>
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	输出形如：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">;fcitx Version 0x03 Table file
KeyCode=abcdefghijklmnopqrstuvwxy
Length=4
Pinyin=@
PinyinLength=12
Prompt=&amp;
ConstructPhrase=^
[Rule]
e2=p11+p12+p21+p22
e3=p11+p21+p31+p32
a4=p11+p21+p31+n11
[Data]
a 工
a 戈
@a 阿          &larr; @ 开头 = <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">type</span>=1（拼音记录）
</code></pre>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	4. 从公网找词库 + 筛选</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">文件：<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/filter_candidates.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">filter_candidates.py</code></a></strong></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.1 数据源（全部开源可下载）</span></h3>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				来源</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				地址（标识）</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				内容</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				备注</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				白霜五笔</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GitHub <code>gaboolic/rime-frost</code> &rarr; <code>cn_dicts_wb/{chars,words}.dict.yaml</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				词 + 五笔码 + 现代语料词频</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				词频用 7 亿字语料重算（GPL-3.0）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				墨奇五笔</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GitHub <code>gaboolic/rime-wubi-sentence</code> &rarr; <code>cn_dicts_wb/base.dict.yaml</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				36 万条，含大量新词/专名</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				码字段是&quot;整句码&quot;，需要还原（MIT）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				现代汉语常用词表</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				gist <code>indiejoseph/eae09c673460aa0b56db</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				5.6 万条规范词表</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				判定&quot;是不是一个词&quot;（无显式许可，仅作判据）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				成语库</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GitHub <code>pwxcoo/chinese-xinhua</code> &rarr; <code>data/idiom.json</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				3.09 万条成语</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				4 字词精确筛选（MIT）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				本机表</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				自己 <code>mb2txt</code> 出来的 dump</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				已有词、单字五笔全码、单字读音</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				差集 + 编码校验基准</td>
</tr>
</tbody>
</table>
</section>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.2 两个词库的码字段怎么还原</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	白霜：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">词 \t 4字母码 \t 词频</code>，直接用。 墨奇：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">词 \t &quot;xx,ax xx,ax &hellip;&quot; \t 权重</code>，每段对应一个字、逗号前是该字前两码，按五笔词组规则还原：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">def</span> <span class="hljs-title" style="color: #4078f2; line-height: 26px;">moqi_to_code</span><span class="hljs-params" style="line-height: 26px;">(s)</span>:</span>
    segs = [x.split(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;,&#39;</span>)[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> x <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> s.split()]
    n = len(segs)
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> n == <span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>:  <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> n == <span class="hljs-number" style="color: #986801; line-height: 26px;">3</span>:  <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + segs[<span class="hljs-number" style="color: #986801; line-height: 26px;">-1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>]
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	（2 字=各前两码；3 字=首字首码+次字首码+末字前两码；4 字以上=前三字首码+末字首码）</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.3 质量判据：用「凝固度」把搭配垃圾挡在门外</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	拼音词库是给<strong style="font-weight: bold;">整句解码</strong>用的，天然塞满 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">有多</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">人是</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">的时候</code> 这类高频二元组。它们对拼音输入有意义，对五笔是纯噪音。</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">PMI（内部凝固度）</strong>：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">PMI = log2( P(w) / &Pi; P(c) )</code>，再除以 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">(词长-1)</code> 做长度归一。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">阈值怎么定</strong>：拿&quot;本机已收录的 2 字词&quot;反推分布&mdash;&mdash;实测 P25 &asymp; 5.0、中位数 &asymp; 8.0 &rarr; 取 <strong style="font-weight: bold; color: black;">归一化 PMI &ge; 5.0</strong>。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">对照：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">人是</code> -2.5、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">中有</code> -0.9、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">是最</code> -0.2、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">有多</code> 1.7（都在底部分位）；<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">题主</code> 11.5、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">刷题</code> 8.2、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">算力</code> 6.8。</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	PMI 不是充分条件（<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">的时候</code> PMI 18.1 也不是词），所以再叠三层：<strong style="font-weight: bold;">虚词字过滤 &rarr; 方位/副词短语过滤 &rarr; 词典交叉</strong>（把&quot;确认是词&quot;和&quot;疑似新词&quot;分成两档）。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	核心片段（<a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/filter_candidates.py" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">filter_candidates.py</code></a>）：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">def</span> <span class="hljs-title" style="color: #4078f2; line-height: 26px;">word_code</span><span class="hljs-params" style="line-height: 26px;">(w)</span>:</span>
    <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;&quot;&quot;用本机单字全码拼词码（比信外部词库更一致）&quot;&quot;&quot;</span>
    cs = [wubi_single.get(ch) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> ch <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> w]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> any(<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> c <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> c <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> cs): <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">None</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(w) == <span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>:   r = cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">elif</span> len(w) == <span class="hljs-number" style="color: #986801; line-height: 26px;">3</span>: r = cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>][:<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">else</span>:             r = cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">2</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] + cs[<span class="hljs-number" style="color: #986801; line-height: 26px;">-1</span>][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> r <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(r) == <span class="hljs-number" style="color: #986801; line-height: 26px;">4</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> r.isalpha() <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">else</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">None</span>

<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">def</span> <span class="hljs-title" style="color: #4078f2; line-height: 26px;">pmi</span><span class="hljs-params" style="line-height: 26px;">(word, freq, tot_w)</span>:</span>
    pc = <span class="hljs-number" style="color: #986801; line-height: 26px;">1.0</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> ch <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> word:
        <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> ch <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> char: <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">None</span>
        pc *= char[ch] / tot_c
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> math.log2((freq / tot_w) / pc) / max(<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>, len(word) - <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>)

<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">def</span> <span class="hljs-title" style="color: #4078f2; line-height: 26px;">keep</span><span class="hljs-params" style="line-height: 26px;">(w)</span>:</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> set(w) &amp; FUNC: <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">False</span>                      <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 含虚词字</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(w) &gt;= <span class="hljs-number" style="color: #986801; line-height: 26px;">3</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> w[<span class="hljs-number" style="color: #986801; line-height: 26px;">-1</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> LOC: <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">False</span>        <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 方位短语</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(w) &gt;= <span class="hljs-number" style="color: #986801; line-height: 26px;">3</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> w[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> DEG: <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">False</span>         <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 副词开头</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> any(g <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> w <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> g <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> GLUE): <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">False</span>           <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 常见口语搭配</span>
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> <span class="hljs-literal" style="color: #0184bb; line-height: 26px;">True</span>
</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.4 三次实际筛选结果（示例）</span></h3>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				批次</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				范围</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				主要过滤</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; background-color: rgb(240, 240, 240); min-width: 85px; text-align: right;">
				阈值</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; background-color: rgb(240, 240, 240); min-width: 85px; text-align: right;">
				产出</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				A 常用词</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				2~3 字，本机缺失，且<strong style="font-weight: bold;">在现汉词表里</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				虚词字 + PMI&ge;5</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				&mdash;</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				1,163</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				B 新词/专名</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				2~3 字，本机缺失，<strong style="font-weight: bold;">不在</strong>词表</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				上述三层 + 搭配黑名单</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				词频&ge;500</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				2,302</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				C 成语</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				4 字，本机缺失，<strong style="font-weight: bold;">在成语库里</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				精确匹配成语库</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				全量</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px; text-align: right;">
				6,738</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	经验：2 字档噪音约 15%，3 字档约 25~30%，4 字档原始候选噪音六成（必须靠成语库/词表分档）。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	5. 程序清单与核心逻辑</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.1 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/mb_table.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>mb_table.py</code></a> &mdash; 码表读写库（核心）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	对外三个函数：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">read(path) -&gt; Table</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">write(path, table)</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">insert_sorted(table, items)</code>。</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">read</code>：按 2.2 的结构解析，最后断言 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">len(records) == recordCount</code>（防格式判断失误）</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">write</code>：头部原样写回 + 记录逐条序列化（码左对齐 NUL 填充、词长含 NUL）</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">insert_sorted</code>：按码插入，<strong style="font-weight: bold; color: black;">同码插在组尾</strong>，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">iIndex</code> 取全局 max 递增</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">insert_sorted</code> 的核心（候选顺序 = 文件顺序，所以插入位置决定排第几）：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">def</span> <span class="hljs-title" style="color: #4078f2; line-height: 26px;">insert_sorted</span><span class="hljs-params" style="line-height: 26px;">(table, new_items)</span>:</span>
    max_idx = max((r[<span class="hljs-number" style="color: #986801; line-height: 26px;">4</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> r <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> table.records), default=<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>)
    add = []
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> code, word, typ <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> new_items:
        max_idx += <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>
        add.append([code, word + <span class="hljs-string" style="color: #50a14f; line-height: 26px;">b&#39;\x00&#39;</span>, typ, <span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>, max_idx])
    add.sort(key=<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">lambda</span> r: (r[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>], r[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>]))

    out, i, ai, recs = [], <span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>, <span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>, table.records
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">while</span> i &lt; len(recs):
        <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> ai &lt; len(add) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> add[ai][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] &lt; recs[i][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>]:
            out.append(add[ai]); ai += <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>
        <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">else</span>:
            cur = recs[i]; out.append(cur); i += <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>
            <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> ai &lt; len(add) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> add[ai][<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>] == cur[<span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>]:   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 走到该码组末尾</span>
                out.append(add[ai]); ai += <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>
    out.extend(add[ai:])
    table.records = out
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">return</span> len(add)
</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.2 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/merge_wubi.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>merge_wubi.py</code></a> &mdash; 并入五笔词条</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	读 CSV（至少含 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">词,五笔码</code>），跳过表里已存在的词，调用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">insert_sorted(..., type=0)</code>。</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">have = {r[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>].rstrip(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">b&#39;\x00&#39;</span>).decode(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;utf-8&#39;</span>, <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;ignore&#39;</span>) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> r <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> t.records}
items = [(row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;五笔码&#39;</span>].encode(), row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;词&#39;</span>].encode(), <span class="hljs-number" style="color: #986801; line-height: 26px;">0</span>)
         <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> row <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> csv.DictReader(open(cand_csv, encoding=<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;utf-8&#39;</span>))
         <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;词&#39;</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> have]
n = mb_table.insert_sorted(t, items)
mb_table.write(dst, t)
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	用法：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">python3 merge_wubi.py &lt;源.mb&gt; &lt;候选.csv&gt; &lt;输出.mb&gt;</code></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.3 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/gen_pinyin.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>gen_pinyin.py</code></a> &mdash; 生成拼音码（含多音字）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	三个要点：词组级注音（避免多音字按单字乱读）、多音备选、按 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">pyCodeLen</code> 截断。 <strong style="font-weight: bold;">关键设计：备选读音必须在&quot;本机表里已出现过的单字读音&quot;白名单内</strong>，否则会造出输入法根本打不出的废码。</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 1) 从 dump 里取单字读音白名单</span>
local = collections.defaultdict(set)
<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> ln <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> body:
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> ln.startswith(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;@&#39;</span>) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39; &#39;</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> ln:
        c, w = ln[<span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>:].split(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39; &#39;</span>, <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>)
        <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(w) == <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>:
            local[w].add(c)

<span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 2) 词组级注音 + 按白名单过滤每个字的读音</span>
base = <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;&#39;</span>.join(lazy_pinyin(w))[:<span class="hljs-number" style="color: #986801; line-height: 26px;">12</span>]
vs = pinyin(w, heteronym=<span class="hljs-literal" style="color: #0184bb; line-height: 26px;">True</span>, style=Style.NORMAL)
vs = [[p <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> p <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> lst <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> p <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> local.get(ch, {p})] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">or</span> lst <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> lst, ch <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> zip(vs, w)]

<span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 3) 组合候选，去重，最多保留 cap 个</span>
<span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> combo <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> itertools.product(*vs):
    p = <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;&#39;</span>.join(combo)[:<span class="hljs-number" style="color: #986801; line-height: 26px;">12</span>]
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> p <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> cands: cands.append(p)
    <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(cands) &gt;= cap: <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">break</span>
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	用法：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">python3 gen_pinyin.py &lt;词表.csv&gt; &lt;输出.csv&gt; &lt;表dump.txt&gt; [每词最多几个码]</code></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.4 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/merge_pinyin.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>merge_pinyin.py</code></a> &mdash; 并入拼音记录</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	与 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">merge_wubi.py</code> 同构，区别是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">type=1</code>，且<strong style="font-weight: bold;">支持跳过冲突码</strong>：</p>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		若某拼音码恰好等于一个&quot;只有唯一候选&quot;的五笔码，插入后会破坏&quot;唯一即上屏&quot;。这类码要放进跳过列表。</p>
</blockquote>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">skip = set((sys.argv[<span class="hljs-number" style="color: #986801; line-height: 26px;">4</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> len(sys.argv) &gt; <span class="hljs-number" style="color: #986801; line-height: 26px;">4</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">else</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;&#39;</span>).split(<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;,&#39;</span>))
items = [(row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;拼音码&#39;</span>].encode(), row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;词&#39;</span>].encode(), <span class="hljs-number" style="color: #986801; line-height: 26px;">1</span>)
         <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">for</span> row <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> csv.DictReader(open(py_csv, encoding=<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;utf-8&#39;</span>))
         <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">if</span> row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;拼音码&#39;</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;拼音码&#39;</span>] <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> skip
         <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">and</span> (row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;词&#39;</span>].encode(), row[<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;拼音码&#39;</span>].encode()) <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">not</span> <span class="hljs-keyword" style="color: #a626a4; line-height: 26px;">in</span> existing]
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	用法：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">python3 merge_pinyin.py &lt;源.mb&gt; &lt;拼音.csv&gt; &lt;输出.mb&gt; [跳过的码,...]</code></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.5 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/filter_candidates.py" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>filter_candidates.py</code></a> &mdash; 候选筛选</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	输入：本机 dump + 字频表（<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">chars.dict.yaml</code>）+ 一个或多个外部词库文件；输出 CSV：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">词,五笔码,词频,归一PMI</code>。 判据见第 4.3 节。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	用法：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">python3 filter_candidates.py &lt;dump.txt&gt; &lt;chars.dict.yaml&gt; &lt;词库1&gt; [词库2 ...] &gt; cand.csv</code></p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	6. 安装与验证</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">6.1 为什么必须先停 fcitx</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	fcitx-table 在<strong style="font-weight: bold;">退出时会重写整个 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">.mb</code></strong>（把内存里的表 + 用户造词落盘）。只要 fcitx 还在跑，你替换的文件可能被覆盖，或它下次退出时把内存旧表写回去。 所以顺序必须是：<strong style="font-weight: bold;">停 &rarr; 备份 &rarr; 基于最新文件重建 &rarr; 替换 &rarr; 启动</strong>。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">6.2 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/apply.sh" style="text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word; border-bottom: 1px solid rgb(30, 107, 184);"><code>apply.sh</code></a>：一键替换（已封装上述顺序）</span></h3>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">./apply.sh &lt;new_table.mb&gt; [before.txt]
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	脚本内部的关键几步：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">pkill -TERM -x fcitx; sleep 3                      <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 1) 停（让它把用户词落盘）</span>
cp -p <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$HOME</span>/wbpy.mb.bak-<span class="hljs-variable" style="color: #986801; line-height: 26px;">$TS</span>&quot;</span>                <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 2) 备份</span>
<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$HERE</span>/mb2txt&quot;</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$NEW</span>&quot;</span> &gt; after.txt                  <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 3) 回读新表</span>
ADD=$(diff &lt;(sort before.txt) &lt;(sort after.txt) | grep -c <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^&gt;&#39;</span>)
LOST=$(diff &lt;(sort before.txt) &lt;(sort after.txt) | grep -c <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^&lt;&#39;</span>)
[ <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$LOST</span>&quot;</span> = <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;0&quot;</span> ] || <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">exit</span> 1                        <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 4) 有丢失就中止，不动原库</span>
cp <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$NEW</span>&quot;</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span>; chmod 600 <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span>                   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 5) 替换</span>
setsid fcitx -d &amp;                                  <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 6) 启动</span>
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	手工等价流程（不用脚本时）：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">MB=<span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$HOME</span>/.config/fcitx/table/wbpy.mb&quot;</span>
pkill -TERM -x fcitx; sleep 3
cp -p <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span> <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$HOME</span>/wbpy.mb.bak-<span class="hljs-variable" style="color: #986801; line-height: 26px;">$(date +%Y%m%d-%H%M%S)</span>&quot;</span>
./mb2txt <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span> &gt; before.txt
python3 merge_wubi.py <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span> cand_wubi.csv after.mb
./mb2txt after.mb &gt; after.txt
diff &lt;(sort before.txt) &lt;(sort after.txt) | grep -c <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^&gt;&#39;</span>   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 新增条数</span>
diff &lt;(sort before.txt) &lt;(sort after.txt) | grep -c <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^&lt;&#39;</span>   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 必须为 0</span>
cp after.mb <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span> &amp;&amp; chmod 600 <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&quot;<span class="hljs-variable" style="color: #986801; line-height: 26px;">$MB</span>&quot;</span>
setsid fcitx -d &amp;</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	&nbsp;</h3>
<ul style="box-sizing: border-box; margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 16px; background-color: rgb(255, 255, 255);">
<li style="box-sizing: border-box;">
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
			<span class="content"></p>
<section style="box-sizing: border-box; margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">无图形界面的 shell 里启动 fcitx 需带上会话变量：<code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">DISPLAY=:0</code>、<code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">XAUTHORITY=$XDG_RUNTIME_DIR/gdm/Xauthority</code>、<code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus</code>。</section>
<p></span></h3>
</li>
<li style="box-sizing: border-box;">
		<span class="content"></p>
<section style="box-sizing: border-box; margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">注意 <code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">fcitx-remote</code> 在没有输入焦点的 shell 里可能返回 0，<strong style="box-sizing: border-box; font-weight: bold; color: black;">不能当判据</strong>；用 <code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">xprop -root | grep XIM_SERVERS</code>（应含 <code style="box-sizing: border-box; font-size: 14px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(30, 107, 184); background-color: rgba(27, 31, 35, 0.05); word-break: break-all;">@server=fcitx</code>）或直接打字判断。</section>
<p></span></li>
</ul>
<div style="box-sizing: border-box;">
	&nbsp;</div>
<p><span class="content">6.3 三层验证</span></p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				层次</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				方法</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				通过标准</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				结构</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				官方 <code>mb2txt</code> 回读 + 全量 <code>diff</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				新增条数准确、<strong style="font-weight: bold;">丢失 0</strong></td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				加载</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				fcitx 启动日志、<code>xprop -root \| grep XIM_SERVERS</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				无表相关报错、<code>@server=fcitx</code> 在</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				功能</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				实际打字：唯一码 + 重码各挑几个</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				唯一码直接上屏；重码在候选里（新词排最后）</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	抽验示例：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">五笔：iiid 泪流满面 / fiml 云淡风轻 / uspy 盖棺定论 / aflf 攻城略地
拼音：leiliuma &rarr; 泪流满面 / yundanfe &rarr; 云淡风轻 / zhifubao &rarr; 支付宝
</code></pre>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">6.4 回滚</span></h3>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">./rollback.sh ~/wbpy.mb.bak-YYYYmmdd-HHMMSS
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	建议每批改动前都备份；确认稳定几天后只留最近一份（每个约 10MB）。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content"><span style="font-size: 16px; color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" style="font-size: 16px;" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	7. 经验与坑（按踩坑顺序）</span></h2>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">别信&quot;码宽 = 码长 + 1&quot;</strong>。真实是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">pyCodeLen + 1</code>（w bpy 表里是 13）。按 4/5 字节解析会整体错位，且因为同码相邻记录&quot;看起来也对&quot;，很难发现。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">前 4 字节不是词长</strong>。它是码字段的中间部分；词长在码字段之后。第一版解析器能 100% &quot;重建&quot;文件（因为原样拷贝了未知字节），但新记录建不出来 &mdash;&mdash; round-trip 一致性只能证明&quot;读懂了&quot;，不能证明&quot;会写&quot;。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">记录必须按码首字符分组</strong>，否则引擎索引失效。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">同码先后 = 文件先后</strong>，插入位置即候选位置。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">iIndex</code> 用全局最大值 +1</strong>，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">iHit</code> 新词写 0，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">type</code>：五笔 0、拼音 1（写错会被当拼音/提示记录）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">拼音码截断到 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">pyCodeLen</code></strong>（12），但因为是前缀匹配，照样可用。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">拼音码若与&quot;唯一候选的五笔码&quot;同码</strong>，会破坏&quot;唯一即上屏&quot;，应跳过。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">fcitx 退出会重写 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">.mb</code></strong>，所以顺序不能颠倒；重建要基于&quot;停之后&quot;的最新文件。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">拼音词库 &ne; 词表</strong>。<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">有多</code>/<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">人是</code>/<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">的时候</code> 是整句解码的 n-gram，必须靠 PMI + 词表交叉剔除。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">4 字词噪音最大</strong>，不要只按词频排；用成语库精确匹配效果最好。</section>
</li>
</ol>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">8. 一次完整操作清单（checklist）</span></h2>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">[ ] git <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">clone</span> https://github.com/codelast/update-freewb-dict-on-linux.git &amp;&amp; <span class="hljs-built_in" style="color: #c18401; line-height: 26px;">cd</span> update-freewb-dict-on-linux   <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 拿到脚本</span>
[ ] ./build_mb2txt.sh                        <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 编译官方工具</span>
[ ] ./mb2txt &lt;词库.mb&gt; &gt; dump.txt             <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 差集基准 + 单字码/读音来源</span>
[ ] 下载外部词库（白霜 / 墨奇 / 现汉词表 / 成语库）
[ ] python3 filter_candidates.py ... &gt; cand.csv
[ ] 人工抽验候选（TOP + 中段随机）
[ ] python3 merge_wubi.py   &lt;源.mb&gt; cand.csv  after.mb
[ ] 可选：python3 gen_pinyin.py / merge_pinyin.py
[ ] ./mb2txt after.mb &gt; after.txt；diff 校验：新增对、丢失 0
[ ] ./apply.sh after.mb          <span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 停服&rarr;备份&rarr;校验&rarr;替换&rarr;重启</span>
[ ] 日志无报错 + xprop 有 fcitx + 实打若干词
[ ] 记下备份路径与回滚命令
</code></pre>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">附：常用命令速查</span></h2>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		以下命令均需在仓库目录下执行。</p>
</blockquote>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: block; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 查看表结构（文本形式）</span>
./mb2txt ~/.config/fcitx/table/wbpy.mb | head -20

<span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 统计词条数 / 拼音记录数</span>
./mb2txt ~/.config/fcitx/table/wbpy.mb | sed -n <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;/<p style='text-align:center;'><span class='MathJax_Preview'>\[Data\]</span><script type='math/tex;  mode=display'>Data</script></p>/,$p&#39;</span> | tail -n +2 | wc -l
./mb2txt ~/.config/fcitx/table/wbpy.mb | grep -c <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^@&#39;</span>

<span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 按码查词</span>
./mb2txt ~/.config/fcitx/table/wbpy.mb | grep <span class="hljs-string" style="color: #50a14f; line-height: 26px;">&#39;^rdug &#39;</span>

<span class="hljs-comment" style="color: #a0a1a7; font-style: italic; line-height: 26px;"># 重启输入法</span>
fcitx -r
</code></pre>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		全部操作只在 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">~/.config/fcitx/table/</code>（词库与备份）与仓库目录（脚本）内进行，不改动系统文件。</p>
</blockquote>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">附：授权与合规（数据来源）</span></h2>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				组件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				来源</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				许可证</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				用途</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				白霜五笔</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>gaboolic/rime-frost</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPL-3.0</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				主要词源 + 现代词频</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				墨奇五笔</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>gaboolic/rime-wubi-sentence</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				MIT</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				新词/专名</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				雾凇拼音（白霜上游）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>iDvel/rime-ice</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPL-3.0</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				间接继承</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				成语库</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>pwxcoo/chinese-xinhua</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				MIT</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				4 字成语判定</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				现代汉语常用词表</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				gist（2014）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				无声明（默认保留）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				仅作&quot;是否成词&quot;判据，未复制内容</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				fcitx4 源码</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>fcitx/fcitx</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPL-2.0</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				编译本地校验工具</td>
</tr>
</tbody>
</table>
</section>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">本项目代码以 <strong style="font-weight: bold; color: black;">MIT</strong> 发布（见仓库 <a href="https://github.com/codelast/update-freewb-dict-on-linux/blob/main/LICENSE" style="text-decoration: none; color: #1e6bb8; word-wrap: break-word; font-weight: bold; border-bottom: 1px solid #1e6bb8;"><code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; background-color: rgba(27, 31, 35, 0.05); font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all;">LICENSE</code></a>）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">本机自用（不分发）</strong>：GPL/MIT 的义务都不触发，无风险。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">若要分发产出的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">.mb</code></strong>：GPL-3.0 部分需提供生成脚本并同许可；MIT 部分保留版权声明；用户自定义词条版权归用户。</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span> 版权声明 <span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</section>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8-ubuntu-%e4%b8%8a%e6%9b%b4%e6%96%b0%e3%80%8c%e6%9e%81%e7%82%b9%e4%ba%94%e7%ac%94%e3%80%8d%e8%af%8d%e5%ba%93%ef%bc%88fcitx4-%e7%a0%81%e8%a1%a8%ef%bc%89/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 有些Windows软件的技术栈真的好老</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%9c%89%e4%ba%9bwindows%e8%bd%af%e4%bb%b6%e7%9a%84%e6%8a%80%e6%9c%af%e6%a0%88%e7%9c%9f%e7%9a%84%e5%a5%bd%e8%80%81/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%9c%89%e4%ba%9bwindows%e8%bd%af%e4%bb%b6%e7%9a%84%e6%8a%80%e6%9c%af%e6%a0%88%e7%9c%9f%e7%9a%84%e5%a5%bd%e8%80%81/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 06:54:03 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[AxMath]]></category>
		<category><![CDATA[移植Linux]]></category>
		<category><![CDATA[软件技术栈]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14273</guid>

					<description><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">
<h1 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 24px;">
	<span class="content">有些Windows软件的技术栈真的好老</span></h1>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		一个 2025 年 7 月发布的安装包，拆开一看，内核停留在 2008 年。</p>
</blockquote>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">1、起因：只是想看看能不能搬到 Linux</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	事情很简单。我手上有一个 Windows 安装包 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">AxMath_Setup_Win_20250713_EN.exe</code>（AxMath，一款小众的数学公式编辑器），我是它的正版注册用户，但我想着能不能在Ubuntu下，用非Wine的方式、非虚拟机的方式使用它呢？这就涉及把它移植到Ubuntu的问题了&#8212;&#8212;如果它是基于Electron之类跨平台的框架开发的，那还真有可能。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	文件名里写着 20250713，也就是 2025 年 7 月发布的版本。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	所以就把它拆包看看。<br />
	<span id="more-14273"></span></p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">2、拆开之后：考古现场</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	安装包是 NSIS 自解压格式，用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">7z</code> 一把就解开了：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">7z&#160;x&#160;AxMath_Setup_Win_20250713_EN.exe&#160;-o&#160;extracted
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	里面的东西很有意思：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">AxMath.exe&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主程序
AxSnap.exe&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;截图/OCR&#160;工具
Register.exe&#160;&#160;&#160;&#160;&#160;&#160;授权注册
AxLaTeX.dll&#160;&#160;&#160;&#160;&#160;&#160;&#160;LaTeX&#160;渲染
AxBDH.dll&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Office&#160;桥接
Microsoft.VC90.MFC/mfc90u.dll&#160;&#160;&#160;&#160;&#160;&#160;&#8592;&#160;注意这个
gdiplus.assembly/GdiPlus.dll
libeay32.dll&#160;/&#160;ssleay32.dll&#160;/&#160;libcurl.dll
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">Microsoft.VC90.MFC</code> 这个目录名就是线索：<strong style="font-weight: bold;">VC90 = Visual C++ 2008</strong>。也就是说，这个 2025 年的软件，跑在 2008 年的运行时上。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%9c%89%e4%ba%9bwindows%e8%bd%af%e4%bb%b6%e7%9a%84%e6%8a%80%e6%9c%af%e6%a0%88%e7%9c%9f%e7%9a%84%e5%a5%bd%e8%80%81/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;">
<h1 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 24px;">
	<span class="content">有些Windows软件的技术栈真的好老</span></h1>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		一个 2025 年 7 月发布的安装包，拆开一看，内核停留在 2008 年。</p>
</blockquote>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">1、起因：只是想看看能不能搬到 Linux</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	事情很简单。我手上有一个 Windows 安装包 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">AxMath_Setup_Win_20250713_EN.exe</code>（AxMath，一款小众的数学公式编辑器），我是它的正版注册用户，但我想着能不能在Ubuntu下，用非Wine的方式、非虚拟机的方式使用它呢？这就涉及把它移植到Ubuntu的问题了&mdash;&mdash;如果它是基于Electron之类跨平台的框架开发的，那还真有可能。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	文件名里写着 20250713，也就是 2025 年 7 月发布的版本。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	所以就把它拆包看看。<br />
	<span id="more-14273"></span></p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">2、拆开之后：考古现场</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	安装包是 NSIS 自解压格式，用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">7z</code> 一把就解开了：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">7z&nbsp;x&nbsp;AxMath_Setup_Win_20250713_EN.exe&nbsp;-o&nbsp;extracted
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	里面的东西很有意思：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">AxMath.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主程序
AxSnap.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;截图/OCR&nbsp;工具
Register.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;授权注册
AxLaTeX.dll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LaTeX&nbsp;渲染
AxBDH.dll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Office&nbsp;桥接
Microsoft.VC90.MFC/mfc90u.dll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&larr;&nbsp;注意这个
gdiplus.assembly/GdiPlus.dll
libeay32.dll&nbsp;/&nbsp;ssleay32.dll&nbsp;/&nbsp;libcurl.dll
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">Microsoft.VC90.MFC</code> 这个目录名就是线索：<strong style="font-weight: bold;">VC90 = Visual C++ 2008</strong>。也就是说，这个 2025 年的软件，跑在 2008 年的运行时上。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	再用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">objdump</code> 一验，实锤：</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				项目</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				实测值</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				含义</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				PE 架构</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				PE32 (x86)</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">32 位</strong></td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				MajorLinkerVersion</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">9.0</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Visual Studio<strong style="font-weight: bold;">2008</strong> 的链接器</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				附带运行库</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>mfc90u.dll</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				MFC 9.0 = VC++ 2008</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				主程序时间戳</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">2025-07-13</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				编译日期很新</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				捆绑 OpenSSL</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">1.0.2d（2015-07-09）</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				早已 EOL</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				捆绑 libcurl</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">7.45.0（2015）</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				十年前的东西</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	一边是 2025 年的时间戳，一边是 2008 年的工具链和 2015 年的第三方库。</p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">3、2025年的软件版本竟然还是32位的</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	很多人的第一反应是：2025年的版本还是32位的？但对这类软件来说，这几乎是必然的。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">3.1 迁移成本和收益不成比例</strong> 一个 MFC 老代码库要从 32 位迁到 64 位、从 VC9 迁到新工具链，构建脚本、第三方依赖、COM 注册&hellip;&hellip;全都得动。而 32 位程序在 64 位 Windows 上靠 WOW64 照样跑，用户完全无感，对小软件团队来说没动力迁移。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">3.2 Office 加载项的&quot;位数枷锁&quot;</strong> AxMath 的核心价值是嵌进 Word / Excel / WPS。它的 COM 组件必须和宿主 Office 的位数一致，而 32 位 Office / WPS 装机量巨大&mdash;&mdash;跟着做 32 位最省事。解包里能看到一堆加载项：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">AxMath.dotm&nbsp;&nbsp;&nbsp;&rarr;&nbsp;Word（含&nbsp;VBA&nbsp;宏）
AxMath.xlam&nbsp;&nbsp;&nbsp;&rarr;&nbsp;Excel
AxMath.ppam&nbsp;&nbsp;&nbsp;&rarr;&nbsp;PowerPoint
WPS/STARTUP/AxMath.dotm&nbsp;&rarr;&nbsp;WPS
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">3.3 轻量应用根本用不上 64 位的好处</strong> 一个公式编辑器，内存占用远不到 2GB。64 位最大的优势（大内存寻址）在这儿毫无意义。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">4、安全问题</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	技术栈老，本身只是&quot;不优雅&quot;。但当我们把范围从&quot;好不好看&quot;换成&quot;安不安全&quot;，问题就严肃了。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">4.1 授权走的是明文 HTTP</strong> <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">Register.exe</code> 里的联网地址是（注意是 UTF-16 宽字符存的，普通搜索搜不到）：</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">
<code class="hljs" style="display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">http://www.axmath.cn:6150/@@@&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&larr;&nbsp;授权服务器
http://121.199.3.143:6150/@@@&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&larr;&nbsp;硬编码备用&nbsp;IP
</code></pre>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	激活码、机器指纹，就这么明文发出去了。在公共 WiFi 下，同网段的攻击者抓个包就能拿到激活码&mdash;&mdash;不需要任何漏洞利用技巧。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">4.2 2015 年的 OpenSSL 1.0.2d</strong> 这个版本之后修的所有 CVE 它都带着。比如 CVE-2016-2107（AES-NI padding oracle），中间人可以利用它解密 HTTPS 会话&mdash;&mdash;也就是说，&quot;用了 HTTPS&quot;在这个版本上并不等于安全。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">4.3 承载漏洞的库没开内存防护</strong></p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				文件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				DllCharacteristics</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				含义</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>Register.exe</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				0x8140</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				ASLR + DEP</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>libcurl.dll</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				0x0140</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				ASLR + DEP</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>libeay32.dll</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">0x0000</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">无 ASLR、无 DEP</strong></td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	名词解释：</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">ASLR</strong>（Address Space Layout Randomization，地址空间布局随机化）：每次程序启动时，把代码、数据、DLL 等加载到随机的内存地址。这样攻击者就无法预知某个函数或数据的固定地址，构造可靠的利用会变得困难。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">DEP</strong>（Data Execution Prevention，数据执行保护，即 NX）：把内存里的数据区标记为&quot;不可执行&quot;。即使攻击者把恶意代码写进了内存，CPU 也会拒绝执行它，从而挡掉一大类&quot;写入即执行&quot;的攻击。</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	一旦 libcurl（7.45.0 存在越界写类漏洞，如 CVE-2016-8617）或 OpenSSL 触发内存破坏，这个&quot;裸奔&quot;的 DLL 会让利用门槛大幅降低。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span> 版权声明 <span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</section>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%9c%89%e4%ba%9bwindows%e8%bd%af%e4%bb%b6%e7%9a%84%e6%8a%80%e6%9c%af%e6%a0%88%e7%9c%9f%e7%9a%84%e5%a5%bd%e8%80%81/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 通过串口终端连接树莓派(CH340)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e9%80%9a%e8%bf%87%e4%b8%b2%e5%8f%a3%e7%bb%88%e7%ab%af%e8%bf%9e%e6%8e%a5%e6%a0%91%e8%8e%93%e6%b4%bech340/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e9%80%9a%e8%bf%87%e4%b8%b2%e5%8f%a3%e7%bb%88%e7%ab%af%e8%bf%9e%e6%8e%a5%e6%a0%91%e8%8e%93%e6%b4%bech340/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 17:55:06 +0000</pubDate>
				<category><![CDATA[Raspberry Pi/树莓派]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[CH340]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[串口]]></category>
		<category><![CDATA[树莓派]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14268</guid>

					<description><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &#34;PingFang SC&#34;, Cambria, Cochin, Georgia, Times, &#34;Times New Roman&#34;, serif;">
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">背景：你是否遇到过&#34;树莓派的WiFi连不上网络，有线连接树莓派也不具备条件&#34;的情况？这个时候，你想通过终端连接到树莓派上还剩下哪些选择？串口就是其中一个可行的办法。对大多数人来说，这种连接方法都算比较少见，但它确实是一个在网络断链时的好方法。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">目标：让 macOS 通过 USB-TTL (CH340) 模块连接树莓派 GPIO 串口，获得一个<strong style="font-weight: bold; color: black;">完全不依赖网络</strong>的终端/登录通道（等同于 SSH 控制台，但走串口线）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">树莓派版本：3B Rev 1.2</section>
</li>
</ul>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">1. 先认识 CH340 模块：它是什么，能帮我们做什么</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.1 CH340 是什么</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	CH340 是一颗国产的&#34;USB 转串口&#34;芯片（这类芯片也常被叫做 USB-UART 桥接芯片）。市面上卖的那种USB-TTL 小板，核心就是这颗芯片，板上通常还会引出一排针脚，标着 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">VCC / 5V / 3V3 / TXD / RXD / GND</code>。<br />
	<span id="more-14268"></span><br />
	下面是我用AI绘制的CH340模块3D图：<br />
	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_1.jpg" style="width: 900px; height: 485px;" /></a></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	下面是我的实拍图：<br />
	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_2.jpg" style="width: 500px; height: 166px;" /></a></p>
<p>	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_3.jpg" style="width: 500px; height: 189px;" /></a><br />
	它做的事情可以一句话讲清楚：<strong style="font-weight: bold;">把你的电脑 USB 口变成一个&#34;串口&#34;</strong>。电脑这边看到的是一个串口设备，另一端（比如树莓派、单片机）看到的是标准的串口信号，CH340 负责在两者之间翻译数据。这样电脑就能通过串口协议和另一台设备互相收发数据了。</p>
<h4 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 18px;">
	<span class="content">关于驱动</span></h4>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	三个主流系统（Windows / macOS / Linux）都有 CH340 的驱动，多数情况下插上就能用，不需要手动装。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	macOS 这边，驱动生效的标志是：系统里出现一个叫 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/cu.usbserial-XXX</code></p>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e9%80%9a%e8%bf%87%e4%b8%b2%e5%8f%a3%e7%bb%88%e7%ab%af%e8%bf%9e%e6%8e%a5%e6%a0%91%e8%8e%93%e6%b4%bech340/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<section data-tool="markdown2wechat编辑器" data-website="https://aizhuanqian.com" id="nice" style="font-size: 16px; padding: 0px 10px; line-height: 1.6; letter-spacing: 0px; word-break: break-word; overflow-wrap: break-word; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;">
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">背景：你是否遇到过&quot;树莓派的WiFi连不上网络，有线连接树莓派也不具备条件&quot;的情况？这个时候，你想通过终端连接到树莓派上还剩下哪些选择？串口就是其中一个可行的办法。对大多数人来说，这种连接方法都算比较少见，但它确实是一个在网络断链时的好方法。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">目标：让 macOS 通过 USB-TTL (CH340) 模块连接树莓派 GPIO 串口，获得一个<strong style="font-weight: bold; color: black;">完全不依赖网络</strong>的终端/登录通道（等同于 SSH 控制台，但走串口线）。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">树莓派版本：3B Rev 1.2</section>
</li>
</ul>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">1. 先认识 CH340 模块：它是什么，能帮我们做什么</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.1 CH340 是什么</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	CH340 是一颗国产的&quot;USB 转串口&quot;芯片（这类芯片也常被叫做 USB-UART 桥接芯片）。市面上卖的那种USB-TTL 小板，核心就是这颗芯片，板上通常还会引出一排针脚，标着 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">VCC / 5V / 3V3 / TXD / RXD / GND</code>。<br />
	<span id="more-14268"></span><br />
	下面是我用AI绘制的CH340模块3D图：<br />
	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_1.jpg" style="width: 900px; height: 485px;" /></a></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	下面是我的实拍图：<br />
	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_2.jpg" style="width: 500px; height: 166px;" /></a></p>
<p>	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="CH340" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_3.jpg" style="width: 500px; height: 189px;" /></a><br />
	它做的事情可以一句话讲清楚：<strong style="font-weight: bold;">把你的电脑 USB 口变成一个&quot;串口&quot;</strong>。电脑这边看到的是一个串口设备，另一端（比如树莓派、单片机）看到的是标准的串口信号，CH340 负责在两者之间翻译数据。这样电脑就能通过串口协议和另一台设备互相收发数据了。</p>
<h4 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 18px;">
	<span class="content">关于驱动</span></h4>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	三个主流系统（Windows / macOS / Linux）都有 CH340 的驱动，多数情况下插上就能用，不需要手动装。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	macOS 这边，驱动生效的标志是：系统里出现一个叫 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/cu.usbserial-XXX</code> 的设备文件。你可以把它理解成&quot;串口的门牌号&quot;&mdash;&mdash;终端程序（比如我们后面要用的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">screen</code>）就是靠打开这个文件来跟串口通信的。名字里的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">XXX</code> 是一串数字，每次插拔可能不一样。所以你插上 CH340 后，先执行下面这条命令确认一下设备在不在：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">ls /dev/cu.usbserial*</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	能看到类似 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/cu.usbserial-110</code> 的输出，就说明驱动没问题，可以继续往下走了。如果什么输出都没有，那多半是驱动没装好。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h4 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 18px;">
	<span class="content">关于电平（电压标准）</span></h4>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	串口信号的电平有两种常见标准：5V 和 3.3V。树莓派的 GPIO 是 <strong style="font-weight: bold;">3.3V</strong> 逻辑，所以接树莓派时要注意别让 5V 电平直接灌进 GPIO 引脚。CH340 小板一般 3.3V/5V 都兼容，本文的接法只用到 TXD、RXD、GND 三根线，不涉及供电脚，所以只要别把 5V 引脚接到树莓派上就行（后面 2 章会细说）。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.2 用它连树莓派，具体能做什么</span></h3>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				用途</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				说明</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">断网时的兜底登录</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				树莓派网络出问题（WiFi 连不上、网线也没条件）时，这是唯一还能进系统改配置、查日志的办法，也是本文的核心场景</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">看启动早期日志</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPIO 串口在系统启动很早期就能输出文字，内核启动卡住时靠它看看到底死在哪一步</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">给单片机下载/调试程序</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Arduino、STM32、ESP32 这类板子常用串口烧录程序、打印调试信息</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">在没网络时传小文件</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				可以用 base64 之类的文本协议走串口慢慢传，9600 波特率下大约 0.8KB/s，只适合传很小的文件</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">接其他 TTL 串口外设</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPS 模块、蓝牙模块、需要 AT 指令的模块等，很多都是串口接口，可以共用这套接线思路</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">学习串口原理</strong></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				串口是最基础的通信接口，折腾一遍能搞明白 tty、波特率、流控这些概念</td>
</tr>
</tbody>
</table>
</section>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">1.3 为什么把它定位成&quot;备用通道&quot;，而不是日常主力</span></h3>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">慢。9600 波特率换算下来每秒大约只有 0.8KB，敲命令、改配置够用，传文件会等到怀疑人生；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">电脑得用一根 USB 线物理连着树莓派附近，人不在旁边就用不了；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);">日常调试当然还是 WiFi/网线 SSH 舒服，串口的意义在于：<strong style="font-weight: bold; color: black;">当网络这条路彻底断了，你还有一条路能进系统</strong>。</section>
</li>
</ul>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">2. 硬件准备与接线</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.1 需要准备的东西</span></h3>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				部件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				说明</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				CH340 USB-TTL 小板</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				网上很常见，板上一排针脚通常标着 5V、VCC、3V3、TXD、RXD、GND</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				杜邦线</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				母对母，准备 3~4 根</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				一台电脑（本文以 macOS 为例）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				装好 CH340 驱动，插上后能看到<code>/dev/cu.usbserial-XXX</code> 设备</td>
</tr>
</tbody>
</table>
</section>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.2 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 接线规则：交叉 + 共地（最容易错的一步）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	先解释一下串口的两根数据线：</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">TXD</strong>：发送（Transmit）&mdash;&mdash;这根线负责&quot;说&quot;；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">RXD</strong>：接收（Receive）&mdash;&mdash;这根线负责&quot;听&quot;。</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	通信要成立，必须<strong style="font-weight: bold;">一方的发送接到另一方的接收</strong>，也就是交叉接：</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				CH340 小板</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				树莓派 40-pin 排针</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GND</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Pin 6 / 9 / 14 / 20 / 25 / 30 / 34 / 39（这些全是 GND，任选一个）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				TXD（发送）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Pin 10，也就是树莓派的 RXD / GPIO15</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				RXD（接收）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				Pin 8，也就是树莓派的 TXD / GPIO14</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				VCC / 3V3 / 5V</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<strong style="font-weight: bold;">一律不接</strong></td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	三个容易踩的坑：</p>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">TXD 和 RXD 必须交叉，绝不能 TXD 对 TXD。</strong> 如果接成 TXD 对 TXD，两边都在&quot;说&quot;、没人&quot;听&quot;，结果就是完全收不到任何数据。记住这个画面：两个人都只对着对方说话、却都把耳朵捂上，谁也听不见谁。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">GND 必须共地。</strong> 意思是 CH340 的地线和树莓派的地线要连在一起，让两边有共同的电压参考点。如果不共地，表现是完全没有输出，或者收到一堆乱码（最常见的现象是收到 0 字节）。这一步看着不起眼，实际上一大半&quot;没反应&quot;的问题都出在它身上。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">不要把 VCC / 3V3 / 5V 接到树莓派上。</strong> 树莓派自己有电源，CH340 小板靠 USB 口供电，两边电源脚对接会造成双电源冲突，严重时可能烧东西。</section>
</li>
</ol>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	另外，杜邦线插拔多了容易接触不良。如果怀疑接触问题，换一根线、或者重新插紧往往就好了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">2.3 接线示意图</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	下面这张图把树莓派 40-pin 排针全部画出来了。排针是竖着排列的：左边一列是奇数号 1、3、5&hellip;，右边一列是偶数号 2、4、6&hellip;，从上往下递增。蓝色高亮的是我们真正用到的三个脚。<br />
	<a href="https://www.codelast.com/" target="_blank"><img decoding="async" alt="" src="https://www.codelast.com/wp-content/uploads/2026/09/CH340_and_rpi.jpg" style="width: 835px; height: 1354px;" /></a></p>
<p>	<span style="letter-spacing: 0px;">图中三个高亮触点分别是：</span></p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">Pin 8</strong>：树莓派的 TXD（GPIO14）&mdash;&mdash;接 CH340 的 RXD；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">Pin 10</strong>：树莓派的 RXD（GPIO15）&mdash;&mdash;接 CH340 的 TXD；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">Pin 20</strong>：GND&mdash;&mdash;图里选它只作示例，实际上树莓派上一堆 GND 脚（Pin 6/9/14/20/25/30/34/39）任选一个接都行。</section>
</li>
</ul>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	再次强调：<strong style="font-weight: bold;">CH340 的 TXD 必须接树莓派的 RXD，CH340 的 RXD 必须接树莓派的 TXD</strong>，其他引脚一律不接。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">3. 树莓派端要改的配置</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	要让树莓派通过 GPIO 串口提供登录服务，需要改三个系统文件。因为本文假设的场景是&quot;树莓派已经没有任何网络连接&quot;，所以先讲怎么在没有网络的情况下修改这些文件，再逐个讲每个文件改什么。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">3.1 没有网络时怎么改系统文件（拔卡方式）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	先认识要改的三个文件：</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				文件</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				所在分区</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				作用</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>/boot/firmware/config.txt</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				boot 分区（FAT32）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				启用 GPIO 串口、决定用哪个 UART（3.2 节）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>/boot/firmware/cmdline.txt</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				boot 分区（FAT32）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				让内核把启动日志输出到串口，并定好波特率（3.3 节）</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>/etc/systemd/system/serial-getty@*.service.d/override.conf</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				系统分区（ext4）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				让系统在串口上启动登录程序（3.4 节）</td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	这里有个背景知识需要先说明：树莓派的 SD 卡（TF 卡）其实分成两个分区。一个是 <strong style="font-weight: bold;">boot 分区</strong>，格式是 FAT32，里面放的是开机要用的配置文件（<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">config.txt</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">cmdline.txt</code> 都在这里）；另一个是 <strong style="font-weight: bold;">系统分区</strong>，格式是 ext4，装着整个操作系统。FAT32 分区在任何电脑上都能直接读写，而 ext4 分区普通电脑默认是看不到的。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	拔卡修改的具体步骤：</p>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">关机断电</strong>：先在树莓派上正常关机，然后断开电源。切记不能带电拔卡，容易损坏文件系统；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">取出 TF 卡</strong>，用读卡器插到电脑上；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">改 boot 分区的文件</strong>：boot 分区是 FAT32，插上后电脑会直接识别。macOS 下它会自动挂载成一个盘，一般叫 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/Volumes/bootfs</code>，直接用文本编辑器打开里面的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">config.txt</code>、<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">cmdline.txt</code> 修改保存就行；Windows、Linux 同理，打开 TF 卡对应的盘符/挂载点就能看到这两个文件；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">系统分区里的文件</strong>：如果你需要改第三个文件（<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial-getty</code> 的 override），它在 ext4 系统分区里，普通电脑默认看不到。macOS 要用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">debugfs</code> 之类的 ext4 工具（需要 root 权限），Windows 可以用 ext2fsd 之类的软件。<strong style="font-weight: bold; color: black;">如果觉得这一步麻烦，可以先跳过它</strong>&mdash;&mdash;先只改 boot 分区里的两个文件，等接上串口发现确实登录不了，再回头处理 3.4 节的问题；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">安全弹出 TF 卡</strong>（macOS 里右键推出），插回树莓派，重新上电。</section>
</li>
</ol>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	两个容易困惑的点，提前说明：</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">路径差异</strong>：新版 Raspberry Pi OS（Debian 12/13）里，boot 分区在系统内挂在 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/firmware/</code>；老版本是挂在 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/</code>。但不管系统内路径怎么写，<strong style="font-weight: bold; color: black;">文件本身就在 boot 分区根目录里</strong>&mdash;&mdash;你拔卡插电脑后，直接看盘符根目录下有没有 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">config.txt</code> 就行，不用管 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/firmware</code> 这种路径。</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">全新卡 vs 用过的卡</strong>：如果你是刚烧录好系统、还没第一次开机的卡，也可以插电脑直接改 boot 分区，效果和改 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/firmware/</code> 一样；如果是已经用过的卡，改之前一定要先正常关机再拔。</section>
</li>
</ul>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">3.2 启用 GPIO 串口，并决定用哪个 UART</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	树莓派 GPIO 上引出的串口默认是关闭的，需要在 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/firmware/config.txt</code> 里打开它。用文本编辑器打开这个文件，在文件末尾追加：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="ini" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">enable_uart=1</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	光打开还不够，树莓派 3 上有个特殊情况需要决定：这颗芯片其实有<strong style="font-weight: bold;">两个串口硬件</strong>&mdash;&mdash;一个叫 <strong style="font-weight: bold;">PL011</strong>（质量好、波特率准，但默认分配给蓝牙用），一个叫 <strong style="font-weight: bold;">mini-UART</strong>（功能弱一些、波特率会随 CPU 频率漂移）。GPIO 引出的串口到底用哪个，由要不要给蓝牙让路决定。有三个方案：</p>
<section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;">
<table>
<thead>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				方案</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				config.txt 里的写法</th>
<th style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; text-align: left; background-color: rgb(240, 240, 240); min-width: 85px;">
				结果</th>
</tr>
</thead>
<tbody style="border: 0;">
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				1. 关闭蓝牙，串口用最好的 PL011</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>dtoverlay=disable-bt</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				GPIO 串口是<code>/dev/ttyAMA0</code>（PL011，波特率最准），但蓝牙彻底没了</td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				2. 串口用 PL011、蓝牙挤到 mini-UART</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				<code>dtoverlay=miniuart-bt</code></td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				理论可行，但在部分树莓派 3 上会导致蓝牙固件加载失败，<strong style="font-weight: bold;">不推荐</strong></td>
</tr>
<tr style="border: 0; border-top: 1px solid #ccc; background-color: white;">
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				3. 什么都不加，维持默认</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				（不加 dtoverlay）</td>
<td style="border-style: solid; border-color: rgb(204, 204, 204); padding: 5px 10px; min-width: 85px;">
				蓝牙正常用 PL011；GPIO 串口退而求其次用 mini-UART，即<code>/dev/ttyS0</code></td>
</tr>
</tbody>
</table>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	怎么选，取决于你要不要蓝牙：</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px;">
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">还要用蓝牙</strong>：选方案 3。GPIO 串口会是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/serial0 -&gt; ttyS0</code>（mini-UART）。因为 mini-UART 的波特率会随 CPU 频率漂移，建议把波特率定在 9600 这种低速档，或者去固定 CPU 频率，否则可能出现乱码；</section>
</li>
<li>
<section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);"><strong style="font-weight: bold; color: black;">不需要蓝牙，只想要最稳定的串口</strong>：选方案 1。GPIO 串口是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/serial0 -&gt; ttyAMA0</code>（PL011），波特率精确，省心。</section>
</li>
</ul>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		后面各小节的命令都以 <strong style="font-weight: bold;">方案 3（设备名 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyS0</code>）</strong> 为例。如果你选了方案 1，把命令里出现的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyS0</code> 全部换成 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyAMA0</code> 即可。</p>
</blockquote>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	顺带一提：<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/serial0</code> 是一个软链接，它总是指向&quot;当前 GPIO 串口实际对应的那个设备&quot;（<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyS0</code> 或 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyAMA0</code>），所以不确定时先执行 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ls -l /dev/serial0</code> 看一眼它指向谁，心里就有数了。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">3.3 让内核把启动信息输出到串口（顺便定波特率）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	Linux 内核启动时的日志默认是输出到屏幕的。我们希望它同时也输出到 GPIO 串口，这样就算树莓派没接屏幕，也能从串口看到启动过程。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	这个行为由 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/boot/firmware/cmdline.txt</code> 控制。用文本编辑器打开它，确认里面有这样一段（注意是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial0</code>，不是别的）：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">console=serial0,9600</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial0</code> 就是 GPIO 串口的软链接名，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">9600</code> 是波特率。如果文件里同时有 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">console=tty1</code> 之类的（那是输出到本地屏幕的），不要删掉它们，只把 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial0</code> 这一段波特率定为 9600 就好。</p>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		波特率这个东西，后面会反复强调：<strong style="font-weight: bold;">发送端和接收端必须用同一个波特率</strong>，否则收到的就是乱码。</p>
</blockquote>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">3.4 让系统在串口上启动登录程序（serial-getty）</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	前面两步只是让内核往串口输出日志，但光有日志还不能登录。要登录，系统里得有一个程序在串口上等着，显示 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">login:</code> 提示符、接受你输入用户名密码&mdash;&mdash;这个程序叫 <strong style="font-weight: bold;">getty</strong>，对应的系统服务是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial-getty@&lt;串口设备&gt;.service</code>。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	树莓派系统在检测到 GPIO 串口启用后，一般会自动启动对应的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial-getty</code> 服务。但有一个很常见的坑：<strong style="font-weight: bold;">getty 的波特率必须和内核 console 的波特率一致</strong>（都是 9600）。如果登录提示符不出现，多半就是 getty 没启动，或者波特率不对。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	手动确认/修正的方法是给 getty 写一个配置文件，强制指定设备和波特率。在树莓派上创建 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf</code>（目录可能要自己建）：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="ini" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">[Service]</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">ExecStart=</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">ExecStart=-/sbin/agetty --noclear --keep-baud ttyS0 9600 vt100</span></code></pre>
</section>
<blockquote data-tool="mdnice编辑器" style="font-size: 0.9em; overflow: auto; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); color: rgb(106, 115, 125); padding: 10px 10px 10px 20px; margin-bottom: 20px; margin-top: 20px;">
<p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">
		如果你的 GPIO 串口实际是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyAMA0</code>（方案 1），就把上面两处 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyS0</code> 换成 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ttyAMA0</code>，文件名也跟着改成 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial-getty@ttyAMA0.service.d/override.conf</code>。</p>
</blockquote>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	然后重新加载 systemd 并启用服务：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">sudo systemctl daemon-reload</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">sudo systemctl enable --now serial-getty@ttyS0.service</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	验证服务确实在跑：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">systemctl is-active serial-getty@ttyS0   # 应该输出 active</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">systemctl list-units | grep ttyS0        # 能看到 serial-getty 在运行</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	到这里，树莓派端的配置就齐了：GPIO 串口已启用、内核往串口输出日志、getty 在串口上等你登录。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">4. macOS 这一端怎么连</span></h2>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.1 先确认设备名</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	CH340 插上后 macOS 会自动给它分配一个设备文件，名字是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/cu.usbserial-XXXX</code>（也可能是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">/dev/tty.usbserial-XXXX</code>）。注意末尾那串数字<strong style="font-weight: bold;">每次重新插拔都可能变</strong>（比如这次是 11310，下次变成 11320，再下次是 110），所以别死记一个名字，每次用之前先查一下：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">ls /dev/cu.usbserial*</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	如果这条命令什么都查不到，说明驱动没装好，去 WCH 官网装 macOS 驱动。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.2 用 screen 连上去</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	macOS 自带的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">screen</code> 命令就能当串口终端用：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">screen /dev/cu.usbserial-110 9600</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	格式是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">screen 设备文件 波特率</code>，把设备名换成你上一步查到的实际名字。连接成功后，按一下回车，应该能看到：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">rpi login:</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	输入树莓派的用户名和密码，就进入 shell 了，用法和 SSH 完全一样。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	退出 screen 的方法：先按 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">Ctrl+A</code>，松开后再按 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">K</code>，最后按 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">y</code> 确认退出。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">4.3 不想开终端？也可以用命令直接收发</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	如果你是脚本/程序要自动化测试串口，不需要交互式终端，可以用下面的方式非交互地验证：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">DEV=/dev/cu.usbserial-110                       # 换成你实际的设备名</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">stty -f &quot;$DEV&quot; 9600 raw -echo                   # 设置波特率 9600，关闭回显</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">(timeout 4 cat &quot;$DEV&quot; &gt; /tmp/rx.txt &amp;)          # 后台启动一个读取，读 4 秒</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">printf &#39;\r&#39; &gt; &quot;$DEV&quot;                            # 往串口写一个回车，触发登录提示</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">cat /tmp/rx.txt                                 # 查看收到的内容，应该能看到 &quot;rpi login:&quot;</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">stty</code> 负责配置串口参数，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">cat</code> 负责读，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">printf</code> 负责写&mdash;&mdash;把串口当成一个文件来读写就行。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">5. 调试记录：踩过的坑</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	下面这些是实际接线、调通过程中遇到的问题。如果你一次就成功了，可以跳过本章；如果哪里不对，按顺序排查通常能解决。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.1 第一次接上：完全没有输出，或者全是乱码</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	刚接上时最常见的两个现象：读串口读到 0 字节（什么都没有），或者读到 40~70 字节的乱码。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	按下面的顺序排查：</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">第 1 步：先确认 CH340 小板本身是好的（环回测试）</strong></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	把 CH340 和树莓派的接线全部断开，然后用一根杜邦线把 CH340 板上的 <strong style="font-weight: bold;">TXD 和 RXD 短接</strong>（直接连在一起）。这样一来，CH340 自己发出去的数据会原路回到自己。然后用 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">screen</code> 连上串口随便敲几个字：如果敲什么回显什么，说明 CH340 小板、USB 线、驱动这一整条链路都是好的，问题出在树莓派那一侧。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	不想开终端的话，也可以用命令自动验证：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">stty -f $DEV 115200 raw -echo</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">(timeout 8 cat $DEV &gt; /tmp/loop.txt &amp;)   # 后台读</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">printf &#39;HELLO_LOOP&#39; &gt; $DEV                # 写入一串测试文字</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">grep HELLO_LOOP /tmp/loop.txt &amp;&amp; echo OK   # 能在读到的内容里找到它 =&gt; 模块正常</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	如果这步通过，说明小板没问题，继续看第 2 步。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">第 2 步：检查 GND 是否共地、TXD/RXD 是否交叉</strong></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	读到的字节数是 0 时，优先怀疑两件事：GND 没接（换一个 GND 引脚试试），或者 TXD/RXD 没交叉。我实际遇到过：把 GND 从 Pin 30 换到 Pin 20 之后，读到的数据从 0 字节一下子变成 182 字节&mdash;&mdash;共地的影响就是这么明显。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	<strong style="font-weight: bold;">第 3 步：把 TXD 和 RXD 两根线对调</strong></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	如果前面都查过还是没数据，把 TXD、RXD 两根线互换位置再试。很多时候数据从无到有，就差这一下。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.2 有数据了，但是全是乱码 &rarr; 波特率不对</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	现象：能收到数据了，但内容完全没法看，全是乱码；而且换了好几档波特率读出来的都是&quot;长度差不多的乱码&quot;。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	这是因为<strong style="font-weight: bold;">两边的波特率不一致</strong>。串口通信里，发送方和接收方必须用同样的波特率（相当于约定同样的说话语速），否则对方听到的就是无意义的声音。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	推荐用&quot;矩阵测试&quot;来找到正确的波特率：树莓派和 macOS 两边同步切到同一个波特率，树莓派持续发一段特征文字，macOS 在另一边读，看哪一档能读出可读的文本。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	树莓派侧（示例用 9600）：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">sudo stty -F /dev/ttyS0 9600 raw -echo        # ttyS0 或 ttyAMA0，按你实际设备名</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">for i in 1 2 3 4; do echo -n &quot;MATRIX_BAUD_9600_$i&quot; &gt; /dev/ttyS0; sleep 0.2; done</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	macOS 侧：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">stty -f $DEV 9600 raw -echo</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">(timeout 4 cat $DEV &gt; /tmp/mx.txt &amp;)</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">grep MATRIX_BAUD /tmp/mx.txt &amp;&amp; echo 通过</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	我实际测试的结果是：<strong style="font-weight: bold;">9600 波特率下两边完全互通，反而 115200 读出来是乱的</strong>&mdash;&mdash;这块 CH340 小板在 115200 这个高速档上精度不稳。所以最后统一把波特率定在 9600（8 数据位、无校验、1 停止位，也就是常说的 8N1），内核 console、getty、macOS 端全部用 9600。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.3 能看到内核日志，但没有 login 提示 &rarr; getty 没起来</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	现象：串口上能看到内核启动的日志，但日志播完就没了，一直没有 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">login:</code> 提示符。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	这说明问题不在硬件，而在系统这边&mdash;&mdash;<strong style="font-weight: bold;">没有程序在串口上等你登录</strong>，也就是 3.4 节说的 getty 没有正确启动，或者它的波特率和 console 不一致。解决办法就是按 3.4 节写好 override 文件、启用对应的 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">serial-getty@&lt;设备&gt;.service</code>。</p>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 20px;">
	<span class="content">5.4 换了个 USB 口，就连不上了 &rarr; 设备名变了</span></h3>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	现象：之前明明连得好好的，换了个 USB 口再插，<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">screen</code> 报错 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">[screen is terminating]</code>。</p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	原因在 4.1 节说过：<strong style="font-weight: bold;">设备名末尾的数字每次插拔都可能变</strong>。换了 USB 口，旧名字就失效了。解决办法很简单：重新执行 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: #1e6bb8; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">ls /dev/cu.usbserial*</code> 查出新的设备名，用新名字重新连接。</p>
<hr data-tool="mdnice编辑器" style="height: 1px; margin: 0; margin-top: 10px; margin-bottom: 10px; border: none; border-top: 1px solid black;" />
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-size: 22px;">
	<span class="content">6. 最终验证（确认可用）</span></h2>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	配置全部完成后，用下面两条验证整个链路是通的。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	交互式验证（macOS 终端里）：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">screen /dev/cu.usbserial-110 9600</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;"># 应该看到 rpi login:，输入用户名密码进入 shell</span></code></pre>
</section>
<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0px; line-height: 26px;">
	非交互式验证（脚本里用）：</p>
<section class="code-snippet__fix code-snippet__js" data-tool="mdnice编辑器" style="font-size: 14px; margin: 10px 0; display: block; color: #333; position: relative; background-color: rgba(0,0,0,0.03); border: 1px solid #f0f0f0; border-radius: 2px; display: flex; line-height: 20px; word-wrap: break-word !important;">
<ul class="code-snippet__line-index code-snippet__js" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; counter-reset: line; flex-shrink: 0; height: 100%; padding: 1em; list-style-type: none; padding: 16px; margin: 0;">
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
<li style="list-style-type: none; text-align: right; line-height: 26px; margin: 0px;">
		<span style="min-width: 1.5em; left: -2.5em; counter-increment: line 1; color: rgba(0, 0, 0, 0.3);">ounter(line</span></li>
</ul>
<pre class="code-snippet__js" data-lang="bash" style="margin-bottom: 10px; margin-top: 0px; overflow-x: auto; padding: 16px; padding-left: 0; white-space: normal; flex: 1; -webkit-overflow-scrolling: touch;">
<code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">printf &#39;\r&#39; &gt; $DEV</span></code><code style="border-radius: 0px; white-space: pre; display: flex; position: relative; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; padding: 0px;"><span class="code-snippet_outer" style="line-height: 26px;">timeout 5 cat $DEV        # 应该能看到 &quot;rpi login:&quot;</span></code></pre>
</section>
</section>
<p></p>
<p>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span> 版权声明 <span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e9%80%9a%e8%bf%87%e4%b8%b2%e5%8f%a3%e7%bb%88%e7%ab%af%e8%bf%9e%e6%8e%a5%e6%a0%91%e8%8e%93%e6%b4%bech340/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 结合大模型(LLM)的函数搜索器 FunctionEvolve 简单实测</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%bb%93%e5%90%88%e5%a4%a7%e6%a8%a1%e5%9e%8bllm%e7%9a%84%e5%87%bd%e6%95%b0%e6%90%9c%e7%b4%a2%e5%99%a8-functionevolve-%e7%ae%80%e5%8d%95%e5%ae%9e%e6%b5%8b/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%bb%93%e5%90%88%e5%a4%a7%e6%a8%a1%e5%9e%8bllm%e7%9a%84%e5%87%bd%e6%95%b0%e6%90%9c%e7%b4%a2%e5%99%a8-functionevolve-%e7%ae%80%e5%8d%95%e5%ae%9e%e6%b5%8b/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sat, 20 Jun 2026 06:20:54 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[1stOpt]]></category>
		<category><![CDATA[FunctionEvolve]]></category>
		<category><![CDATA[Symbolic Regression]]></category>
		<category><![CDATA[公式拟合]]></category>
		<category><![CDATA[数值优化]]></category>
		<category><![CDATA[最优化]]></category>
		<category><![CDATA[符号回归搜索]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14229</guid>

					<description><![CDATA[<blockquote>
<p>
		<strong>系统</strong>：MacOS</p>
<p>
		<strong>Python版本</strong>：3.12</p>
<p>
		<strong>测试时间</strong>：2026-06-19</p>
</blockquote>
<p>
	不知道大家有没有做过&#34;从数据里猜测其符合什么样的y=f(x)数学公式&#34;这样的事情？在很多年前没有AI的时代，这个领域基本是欧美软件的天下，后来出现了一个石破天惊的国产软件1stOpt( <a href="http://www.7d-soft.com/">http://www.7d-soft.com/</a> )打破了它们的垄断，在当年算是国产软件在这个领域取得的重大成就。 巧了，这两天我刚好看到科技媒体报道了一个新的国产开源软件 <strong>FunctionEvolve</strong> ，正是和解决此类问题有关，于是我去了解了一下，并且拿它做了一些简单的测试，写成此文。<br />
	本站的关联文章链接：<a href="https://www.codelast.com/?p=7364" target="_blank">最优化/Optimization文章合集</a></p>
<p>
<span id="more-14229"></span>	<br />
	在正文开始之前我想先闲聊一下，文中测试使用的大模型是DeepSeek V4 Flash，测试过程中总共用了30多万token，花费0.19元，由于任务的性质缓存命中率很低，但DS定价太便宜所以几乎没花钱。</p>
<p>
	下面开始正文。</p>
<p>
	<strong>FunctionEvolve</strong> （ <a href="https://github.com/Phoinikas03/FunctionEvolve">https://github.com/Phoinikas03/FunctionEvolve</a> ）是一个符号回归（Symbolic Regression）搜索框架，核心目标是从数值数据中自动发现数学公式。它采用 <strong>LLM + 传统数值优化</strong> 的混合架构：LLM 负责分析领域知识、生成种子公式、选择父本和定向变异建议；传统优化器（DE / CMA-ES / L-BFGS-B / TRF）负责拟合公式中的参数。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 id="-">
	同类软件一览</h3>
<p>
	符号回归和自动公式发现领域已有不少成熟工具，按原理大致可分为两类：</p>
<table>
<thead>
<tr>
<th>
				类别</th>
<th>
				代表软件</th>
<th>
				国别</th>
<th>
				核心技术</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>传统全局优化</strong></td>
<td>
				<strong>1stOpt</strong></td>
<td>
				🇨🇳 国产</td>
<td>
				UGO（通用全局优化），无需初值</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				MATLAB Curve Fitting</td>
<td>
				🇺🇸</td>
<td>
				Trust-Region / Levenberg-Marquardt</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				OriginPro</td>
<td>
				🇺🇸</td>
<td>
				Levenberg-Marquardt / 全局优化</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				DataFit</td>
<td>
				🇺🇸</td>
<td>
				多算法自动搜索</td>
</tr>
<tr>
<td>
				<strong>遗传编程 (GP)</strong></td>
<td>
				Eureqa</td>
<td>
				🇺🇸</td>
<td>
				遗传编程符号回归（最早商业化的 GP 工具）</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				PySR</td>
<td>
				🌍 开源</td>
<td>
				遗传编程（Python 库）</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				GPTIPS</td>
<td>
				🇬🇧</td>
<td>
				多基因遗传编程（MATLAB）</td>
</tr>
<tr>
<td>
				&#160;</td>
<td>
				gplearn</td>
<td>
				🌍 开源</td>
<td>
				遗传编程（Python 库）</td>
</tr>
<tr>
<td>
				<strong>LLM + 优化</strong></td>
<td>
				<strong>FunctionEvolve</strong> 🌟</td>
<td>
				🌍 开源</td>
<td>
				LLM 指导搜索方向 + 数值优化器拟合参数</td>
</tr>
</tbody>
</table>
<p>
	<strong>重点说明：1stOpt（七维高科）</strong></p>
<p>
	我很多年以前用过几次 1stOpt，当时对它留下了深刻印象（不知道现在是否还在维护），所以这里单独介绍一下。</p>
<p>
	1stOpt 是国内 7D-Soft 开发的数值优化分析软件，在工程和科研领域有大量用户。它的核心特点是：</p>
<ul>
<li>
		<strong>无需人工初值</strong> &#8212; 传统工具（如 MATLAB）做曲线拟合时，参数初值给不对就会发散或收敛到局部最优。1stOpt 内置 <strong>UGO（通用全局优化）</strong> 算法族，号称&#34;万用公式，任意初值&#34;。</li>
<li>
		<strong>公式模板驱动</strong> &#8212; 用户提供公式骨架（如 <code>y = a*x^b + c*e^(d*x)</code>），1stOpt 负责搜索最优参数。和 FunctionEvolve 相比，1stOpt 的公式结构需要<strong>人先指定</strong>，FunctionEvolve 则连结构也可以<strong>自动发现</strong>。</li>
<li>
		<strong>适用场景</strong> &#8212; 曲线/曲面拟合、非线性回归、参数估计、微分方程求解、工程反演。</li>
<li>
		<strong>局限</strong> &#8212; 商业软件、闭源、Windows 独占。公式结构依赖用户经验，无法自动探索未知结构。</li>
</ul>
<h2 id="-functionevolve-">
	在 FunctionEvolve 中，大模型起什么作用</h2>
<p>
	<strong>LLM 起的是&#34;搜索方向指导&#34;作用，数学计算由传统优化器完成。</strong></p>
<p>
	FunctionEvolve 是 <strong>LLM + 传统数值优化 的混合架构</strong>，LLM 不做数学计算。</p>
<hr />
<h2 id="-">
	完整工作流</h2>
<table>
<thead>
<tr>
<th>
				阶段</th>
<th>
				组件</th>
<th>
				是否用 LLM</th>
<th>
				作用</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>① 领域分析</strong></td>
<td>
				<code>Generator</code></td>
<td>
				✅ LLM</td>
<td>
				分析问题属于什么领域（物理/化学/生物...），给出该领域常见公式模板</td></tr></tbody></table>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%bb%93%e5%90%88%e5%a4%a7%e6%a8%a1%e5%9e%8bllm%e7%9a%84%e5%87%bd%e6%95%b0%e6%90%9c%e7%b4%a2%e5%99%a8-functionevolve-%e7%ae%80%e5%8d%95%e5%ae%9e%e6%b5%8b/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<blockquote>
<p>
		<strong>系统</strong>：MacOS</p>
<p>
		<strong>Python版本</strong>：3.12</p>
<p>
		<strong>测试时间</strong>：2026-06-19</p>
</blockquote>
<p>
	不知道大家有没有做过&quot;从数据里猜测其符合什么样的y=f(x)数学公式&quot;这样的事情？在很多年前没有AI的时代，这个领域基本是欧美软件的天下，后来出现了一个石破天惊的国产软件1stOpt( <a href="http://www.7d-soft.com/">http://www.7d-soft.com/</a> )打破了它们的垄断，在当年算是国产软件在这个领域取得的重大成就。 巧了，这两天我刚好看到科技媒体报道了一个新的国产开源软件 <strong>FunctionEvolve</strong> ，正是和解决此类问题有关，于是我去了解了一下，并且拿它做了一些简单的测试，写成此文。<br />
	本站的关联文章链接：<a href="https://www.codelast.com/?p=7364" target="_blank">最优化/Optimization文章合集</a></p>
<p>
<span id="more-14229"></span>	<br />
	在正文开始之前我想先闲聊一下，文中测试使用的大模型是DeepSeek V4 Flash，测试过程中总共用了30多万token，花费0.19元，由于任务的性质缓存命中率很低，但DS定价太便宜所以几乎没花钱。</p>
<p>
	下面开始正文。</p>
<p>
	<strong>FunctionEvolve</strong> （ <a href="https://github.com/Phoinikas03/FunctionEvolve">https://github.com/Phoinikas03/FunctionEvolve</a> ）是一个符号回归（Symbolic Regression）搜索框架，核心目标是从数值数据中自动发现数学公式。它采用 <strong>LLM + 传统数值优化</strong> 的混合架构：LLM 负责分析领域知识、生成种子公式、选择父本和定向变异建议；传统优化器（DE / CMA-ES / L-BFGS-B / TRF）负责拟合公式中的参数。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 id="-">
	同类软件一览</h3>
<p>
	符号回归和自动公式发现领域已有不少成熟工具，按原理大致可分为两类：</p>
<table>
<thead>
<tr>
<th>
				类别</th>
<th>
				代表软件</th>
<th>
				国别</th>
<th>
				核心技术</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>传统全局优化</strong></td>
<td>
				<strong>1stOpt</strong></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1e8-1f1f3.png" alt="🇨🇳" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 国产</td>
<td>
				UGO（通用全局优化），无需初值</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				MATLAB Curve Fitting</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1fa-1f1f8.png" alt="🇺🇸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				Trust-Region / Levenberg-Marquardt</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				OriginPro</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1fa-1f1f8.png" alt="🇺🇸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				Levenberg-Marquardt / 全局优化</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				DataFit</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1fa-1f1f8.png" alt="🇺🇸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				多算法自动搜索</td>
</tr>
<tr>
<td>
				<strong>遗传编程 (GP)</strong></td>
<td>
				Eureqa</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1fa-1f1f8.png" alt="🇺🇸" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				遗传编程符号回归（最早商业化的 GP 工具）</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				PySR</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f30d.png" alt="🌍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 开源</td>
<td>
				遗传编程（Python 库）</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				GPTIPS</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1ec-1f1e7.png" alt="🇬🇧" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				多基因遗传编程（MATLAB）</td>
</tr>
<tr>
<td>
				&nbsp;</td>
<td>
				gplearn</td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f30d.png" alt="🌍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 开源</td>
<td>
				遗传编程（Python 库）</td>
</tr>
<tr>
<td>
				<strong>LLM + 优化</strong></td>
<td>
				<strong>FunctionEvolve</strong> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f31f.png" alt="🌟" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f30d.png" alt="🌍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 开源</td>
<td>
				LLM 指导搜索方向 + 数值优化器拟合参数</td>
</tr>
</tbody>
</table>
<p>
	<strong>重点说明：1stOpt（七维高科）</strong></p>
<p>
	我很多年以前用过几次 1stOpt，当时对它留下了深刻印象（不知道现在是否还在维护），所以这里单独介绍一下。</p>
<p>
	1stOpt 是国内 7D-Soft 开发的数值优化分析软件，在工程和科研领域有大量用户。它的核心特点是：</p>
<ul>
<li>
		<strong>无需人工初值</strong> &mdash; 传统工具（如 MATLAB）做曲线拟合时，参数初值给不对就会发散或收敛到局部最优。1stOpt 内置 <strong>UGO（通用全局优化）</strong> 算法族，号称&quot;万用公式，任意初值&quot;。</li>
<li>
		<strong>公式模板驱动</strong> &mdash; 用户提供公式骨架（如 <code>y = a*x^b + c*e^(d*x)</code>），1stOpt 负责搜索最优参数。和 FunctionEvolve 相比，1stOpt 的公式结构需要<strong>人先指定</strong>，FunctionEvolve 则连结构也可以<strong>自动发现</strong>。</li>
<li>
		<strong>适用场景</strong> &mdash; 曲线/曲面拟合、非线性回归、参数估计、微分方程求解、工程反演。</li>
<li>
		<strong>局限</strong> &mdash; 商业软件、闭源、Windows 独占。公式结构依赖用户经验，无法自动探索未知结构。</li>
</ul>
<h2 id="-functionevolve-">
	在 FunctionEvolve 中，大模型起什么作用</h2>
<p>
	<strong>LLM 起的是&quot;搜索方向指导&quot;作用，数学计算由传统优化器完成。</strong></p>
<p>
	FunctionEvolve 是 <strong>LLM + 传统数值优化 的混合架构</strong>，LLM 不做数学计算。</p>
<hr />
<h2 id="-">
	完整工作流</h2>
<table>
<thead>
<tr>
<th>
				阶段</th>
<th>
				组件</th>
<th>
				是否用 LLM</th>
<th>
				作用</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>① 领域分析</strong></td>
<td>
				<code>Generator</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> LLM</td>
<td>
				分析问题属于什么领域（物理/化学/生物...），给出该领域常见公式模板</td>
</tr>
<tr>
<td>
				<strong>② 种子生成</strong></td>
<td>
				<code>Generator</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> LLM</td>
<td>
				基于领域知识，生成 20 个初始候选公式（带参数占位符 c0, c1...）</td>
</tr>
<tr>
<td>
				<strong>③ 参数拟合</strong></td>
<td>
				<code>StructureOptimizer</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>纯数值</strong></td>
<td>
				VARPRO + DE + CMA-ES + L-BFGS-B，拟合 c0, c1... 的最优值</td>
</tr>
<tr>
<td>
				<strong>④ 评估</strong></td>
<td>
				<code>Evaluator</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>纯数值</strong></td>
<td>
				计算 NMSE（归一化均方误差）</td>
</tr>
<tr>
<td>
				<strong>⑤ 选父本</strong></td>
<td>
				<code>Selector</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> LLM</td>
<td>
				看当前进化树所有公式的 NMSE 和结构，决定下一轮&quot;从哪些公式出发&quot;</td>
</tr>
<tr>
<td>
				<strong>⑥ 结构变异</strong></td>
<td>
				<code>ASTMutator</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>规则引擎</strong></td>
<td>
				程序化地删子树、加项、拆函数包装，生成候选变体</td>
</tr>
<tr>
<td>
				<strong>⑦ 结构建议</strong></td>
<td>
				<code>LLMMutator</code></td>
<td>
				<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> LLM</td>
<td>
				&quot;试试加个 sin 项&quot;、&quot;试试把 x&sup2; 换成 exp(x)&quot;</td>
</tr>
<tr>
<td>
				<strong>⑧ 回到 ③</strong></td>
<td>
				循环</td>
<td>
				&mdash;</td>
<td>
				拟合 &rarr; 评估 &rarr; 选父本 &rarr; 变异 &rarr; 再拟合...</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="-">
	优化算法详情</h2>
<p>
	所有参数拟合（阶段③）由 <code>StructureOptimizer</code> 执行，它是一个多策略流水线。</p>
<h3 id="-4-">
	第三方库提供的基础算法（4 个）</h3>
<table>
<thead>
<tr>
<th>
				算法</th>
<th>
				第三方来源</th>
<th>
				独立包装文件</th>
<th>
				StructureOptimizer 中的用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>L-BFGS-B</strong></td>
<td>
				<code>scipy.optimize.minimize</code></td>
<td>
				<code>optimizer/lbfgs.py</code></td>
<td>
				局部精修（全局搜索后的细化）；Pow 指数对齐后的重拟合</td>
</tr>
<tr>
<td>
				<strong>DE (差分进化)</strong></td>
<td>
				<code>scipy.optimize.differential_evolution</code></td>
<td>
				<code>optimizer/de.py</code></td>
<td>
				全局搜索主路径之一（<code>_run_de</code>）</td>
</tr>
<tr>
<td>
				<strong>CMA-ES</strong></td>
<td>
				<code>cmaes</code> 库</td>
<td>
				<code>optimizer/cma.py</code></td>
<td>
				全局搜索主路径之一（<code>_run_cma</code>）；DE 的并行兜底</td>
</tr>
<tr>
<td>
				<strong>TRF (Trust Region Reflective)</strong></td>
<td>
				<code>scipy.optimize.least_squares</code></td>
<td>
				<code>optimizer/least_squares.py</code></td>
<td>
				全局搜索路径之一（<code>_run_trf</code>）</td>
</tr>
</tbody>
</table>
<h3 id="-3-">
	项目自身实现的策略（3 个）</h3>
<table>
<thead>
<tr>
<th>
				策略</th>
<th>
				所在方法 (structure.py)</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>① VARPRO (变量投影分解)</strong></td>
<td>
				<code>_try_varpro</code></td>
<td>
				将参数分解为<strong>线性 + 非线性</strong>两组：线性组用 <code>np.linalg.lstsq</code> 直接 OLS 求解，非线性组用基础算法搜索。本质是降维策略</td>
</tr>
<tr>
<td>
				<strong>② Compound-Pow 预搜索</strong></td>
<td>
				<code>_try_pow_presearch</code></td>
<td>
				检测公式中 <code>x^(c)</code> 且底数含其他参数的情况，枚举候选有理指数（1, 2, 1/2, 1/3...），固定指数后用 VARPRO 拟合其余参数</td>
</tr>
<tr>
<td>
				<strong>③ Pow 指数对齐</strong></td>
<td>
				<code>_snap_pow_and_refit</code> + <code>_pow_rational_grid</code></td>
<td>
				将拟合出的浮点指数对齐到最接近的有理数/整数，再用 L-BFGS-B 重新拟合其他参数</td>
</tr>
</tbody>
</table>
<h3 id="structureoptimizer-">
	StructureOptimizer 执行流水线</h3>
<pre>
<code>输入: 公式骨架 + 数据
  │
  ├─ ① <span class="hljs-selector-tag">Pow</span> 预搜索 (Compound-Pow pre-search)
  │   枚举候选指数，固定后用 <span class="hljs-selector-tag">VARPRO</span> 拟合其余参数
  │
  ├─ ② <span class="hljs-selector-tag">VARPRO</span> 分解 (主路径)
  │   线性参数 &rarr; <span class="hljs-selector-tag">np</span><span class="hljs-selector-class">.linalg</span><span class="hljs-selector-class">.lstsq</span> <span class="hljs-selector-tag">OLS</span> 求解
  │   非线性参数 &rarr; <span class="hljs-selector-tag">DE</span> / <span class="hljs-selector-tag">CMA</span> / <span class="hljs-selector-tag">TRF</span> 并行搜索
  │
  ├─ ③ 并行兜底 (DE / CMA / TRF 同时跑, 取最优)
  │
  ├─ ④ <span class="hljs-selector-tag">L-BFGS-B</span> 局部精修
  │
  ├─ ⑤ <span class="hljs-selector-tag">Pow</span> 指数对齐 <span class="hljs-selector-tag">&amp;</span> 重拟合
  │
  └─ 输出: 最优参数 + <span class="hljs-selector-tag">NMSE</span>
</code></pre>
<p>
	所有路径均有<strong>超时保护</strong>和<strong>多次重启</strong>机制。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h2 id="-">
	关键源码位置</h2>
<table>
<thead>
<tr>
<th>
				组件</th>
<th>
				文件</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				主入口 &amp; 装配</td>
<td>
				<code>main.py</code></td>
</tr>
<tr>
<td>
				搜索循环</td>
<td>
				<code>src/search.py</code>（<code>TreeSearch.run()</code>）</td>
</tr>
<tr>
<td>
				LLM 生成器</td>
<td>
				<code>src/generator.py</code></td>
</tr>
<tr>
<td>
				LLM 选择器</td>
<td>
				<code>src/selector.py</code></td>
</tr>
<tr>
<td>
				LLM 变异器</td>
<td>
				<code>src/mutator.py</code></td>
</tr>
<tr>
<td>
				AST 规则变异器</td>
<td>
				<code>src/mutator.py</code>（<code>ASTMutator</code> 类）</td>
</tr>
<tr>
<td>
				参数优化器总管</td>
<td>
				<code>src/optimizer/structure.py</code>（<code>StructureOptimizer</code>）</td>
</tr>
<tr>
<td>
				L-BFGS-B 优化器</td>
<td>
				<code>src/optimizer/lbfgs.py</code></td>
</tr>
<tr>
<td>
				DE 优化器</td>
<td>
				<code>src/optimizer/de.py</code></td>
</tr>
<tr>
<td>
				CMA-ES 优化器</td>
<td>
				<code>src/optimizer/cma.py</code></td>
</tr>
<tr>
<td>
				Least-Squares 优化器</td>
<td>
				<code>src/optimizer/least_squares.py</code></td>
</tr>
<tr>
<td>
				优化器基类 &amp; 工具</td>
<td>
				<code>src/optimizer/base.py</code></td>
</tr>
<tr>
<td>
				评估器</td>
<td>
				<code>src/evaluator.py</code></td>
</tr>
<tr>
<td>
				进化树</td>
<td>
				<code>src/evolution_tree.py</code></td>
</tr>
<tr>
<td>
				LLM 配置</td>
<td>
				<code>llm_config.yaml</code></td>
</tr>
</tbody>
</table>
<h2 id="-">
	一句话总结</h2>
<blockquote>
<p>
		<strong>LLM 是&quot;策略师&quot;&mdash;&mdash;告诉你该往哪个方向找公式；数学优化器是&quot;计算器&quot;&mdash;&mdash;实际算出参数值。</strong></p>
<p>
		LLM 不碰任何数值计算。所有参数拟合由 <code>StructureOptimizer</code> 以 <strong>VARPRO &rarr; DE/CMA/TRF（并行全局搜索）&rarr; L-BFGS-B（局部精修）&rarr; Pow 指数对齐</strong> 的多层流水线完成。</p>
</blockquote>
<hr />
<h2 id="-">
	完整测试流程</h2>
<blockquote>
<p>
		以下是从零开始创建测试数据、搭建环境、运行测试、清理环境的完整步骤记录。&nbsp;</p>
</blockquote>
<h3 id="-">
	测试目标</h3>
<p>
	验证 FunctionEvolve 能否从数值数据中自动发现复杂公式：</p>
<p>
	 <span class='MathJax_Preview'>\(y = \frac{\sin(x_1 x_2)}{\cos(x_3) + 1.5} + e^{-x_2} \cdot \ln(|x_4| + 1) + \frac{x_1 x_3}{1 + x_5^2}\)</span><script type='math/tex'>y = \frac{\sin(x_1 x_2)}{\cos(x_3) + 1.5} + e^{-x_2} \cdot \ln(|x_4| + 1) + \frac{x_1 x_3}{1 + x_5^2}</script> </p>
<h3 id="-">
	步骤一览</h3>
<pre>
<code><span class="hljs-keyword">Step</span> <span class="hljs-number">1</span>: 生成测试数据集
<span class="hljs-keyword">Step</span> <span class="hljs-number">2</span>: 创建临时 Python 环境并安装依赖
<span class="hljs-keyword">Step</span> <span class="hljs-number">3</span>: 编写测试脚本
<span class="hljs-keyword">Step</span> <span class="hljs-number">4</span>: 运行测试
<span class="hljs-keyword">Step</span> <span class="hljs-number">5</span>: 查看结果
<span class="hljs-keyword">Step</span> <span class="hljs-number">6</span>: 删除临时环境
</code></pre>
<hr />
<h3 id="step-1-">
	Step 1：生成测试数据集</h3>
<pre>
<code class="lang-bash"><span class="hljs-keyword">cd</span> /path/<span class="hljs-keyword">to</span>/FunctionEvolve
<span class="hljs-keyword">python3</span> datasets/<span class="hljs-keyword">z</span>/generate_complex_dataset.<span class="hljs-keyword">py</span> --noise-std <span class="hljs-number">0.02</span>
</code></pre>
<h4 id="-">
	生成程序完整源码</h4>
<p>
	保存为 <code>datasets/z/generate_complex_dataset.py</code>：</p>
<pre>
<code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>
<span class="hljs-string">&quot;&quot;</span><span class="hljs-string">&quot;
生成一个复杂公式的符号回归数据集，用于验证 FunctionEvolve 的效果。

公式（5 个输入变量，混合三角函数、指数、对数、有理分式）:

    sin(x1 * x2)                              x1 * x3
y = ──────────── + exp(-x2) * ln(|x4| + 1) + ─────────
    cos(x3) + 1.5                             1 + x5&sup2;


输出:
  datasets/z/
    dataset.npz        &mdash; NumPy 压缩格式（直接用 from_arrays 加载）
    dataset.csv        &mdash; CSV 文本格式（肉眼查看用）
    ground_truth.txt   &mdash; 真实公式说明
    preview.txt        &mdash; 数据统计摘要
&quot;</span><span class="hljs-string">&quot;&quot;</span>

from __future__ <span class="hljs-built_in">import</span> annotations
<span class="hljs-built_in">import</span> argparse
from pathlib <span class="hljs-built_in">import</span> Path
<span class="hljs-built_in">import</span> numpy as np

<span class="hljs-attr">GROUND_TRUTH_EXPRESSION</span> = (
    <span class="hljs-string">&quot;sin(x1 * x2) / (cos(x3) + 1.5) + exp(-x2) * log(abs(x4) + 1) + x1 * x3 / (1 + x5**2)&quot;</span>
)

<span class="hljs-attr">GROUND_TRUTH_SYMBOLS</span> = [<span class="hljs-string">&quot;x1&quot;</span>, <span class="hljs-string">&quot;x2&quot;</span>, <span class="hljs-string">&quot;x3&quot;</span>, <span class="hljs-string">&quot;x4&quot;</span>, <span class="hljs-string">&quot;x5&quot;</span>]
<span class="hljs-attr">RNG</span> = np.random.RandomState(<span class="hljs-number">42</span>)


def _safe_log_abs(x):
    return np.log(np.abs(x) + <span class="hljs-number">1.0</span>)


def ground_truth_y(X):
    x1, x2, x3, x4, <span class="hljs-attr">x5</span> = X[:, <span class="hljs-number">0</span>], X[:, <span class="hljs-number">1</span>], X[:, <span class="hljs-number">2</span>], X[:, <span class="hljs-number">3</span>], X[:, <span class="hljs-number">4</span>]
    <span class="hljs-attr">term1</span> = np.sin(x1 * x2) / (np.cos(x3) + <span class="hljs-number">1.5</span>)
    <span class="hljs-attr">term2</span> = np.exp(-x2) * _safe_log_abs(x4)
    <span class="hljs-attr">term3</span> = x1 * x3 / (<span class="hljs-number">1.0</span> + x5**<span class="hljs-number">2</span>)
    return term1 + term2 + term3


def main():
    <span class="hljs-attr">parser</span> = argparse.ArgumentParser(<span class="hljs-attr">description=&quot;生成复杂符号回归数据集&quot;)</span>
    parser.add_argument(<span class="hljs-string">&quot;--n-train&quot;</span>, <span class="hljs-attr">type=int,</span> <span class="hljs-attr">default=2000)</span>
    parser.add_argument(<span class="hljs-string">&quot;--n-test&quot;</span>, <span class="hljs-attr">type=int,</span> <span class="hljs-attr">default=500)</span>
    parser.add_argument(<span class="hljs-string">&quot;--noise-std&quot;</span>, <span class="hljs-attr">type=float,</span> <span class="hljs-attr">default=0.0)</span>
    parser.add_argument(<span class="hljs-string">&quot;--output-dir&quot;</span>, <span class="hljs-attr">type=str,</span> <span class="hljs-attr">default=None)</span>
    <span class="hljs-attr">args</span> = parser.parse_args()

    <span class="hljs-attr">out_dir</span> = Path(args.output_dir) <span class="hljs-keyword">if</span> args.output_dir <span class="hljs-keyword">else</span> Path(__file__).resolve().parent
    out_dir.mkdir(<span class="hljs-attr">parents=True,</span> <span class="hljs-attr">exist_ok=True)</span>

    <span class="hljs-comment"># 生成训练集</span>
    <span class="hljs-attr">X_train</span> = RNG.uniform(<span class="hljs-attr">low=-3.0,</span> <span class="hljs-attr">high=3.0,</span> <span class="hljs-attr">size=(args.n_train,</span> <span class="hljs-number">5</span>))
    <span class="hljs-attr">y_train</span> = ground_truth_y(X_train)
    <span class="hljs-keyword">if</span> args.noise_std &gt; <span class="hljs-number">0</span>:
        y_train += RNG.normal(<span class="hljs-number">0</span>, args.noise_std, <span class="hljs-attr">size=args.n_train)</span>

    <span class="hljs-comment"># 生成测试集</span>
    <span class="hljs-attr">rng_test</span> = np.random.RandomState(<span class="hljs-number">2024</span>)
    <span class="hljs-attr">X_test</span> = rng_test.uniform(<span class="hljs-attr">low=-3.0,</span> <span class="hljs-attr">high=3.0,</span> <span class="hljs-attr">size=(args.n_test,</span> <span class="hljs-number">5</span>))
    <span class="hljs-attr">y_test</span> = ground_truth_y(X_test)
    <span class="hljs-keyword">if</span> args.noise_std &gt; <span class="hljs-number">0</span>:
        y_test += rng_test.normal(<span class="hljs-number">0</span>, args.noise_std, <span class="hljs-attr">size=args.n_test)</span>

    <span class="hljs-comment"># 保存 NumPy 格式</span>
    np.savez(out_dir / <span class="hljs-string">&quot;dataset.npz&quot;</span>,
             <span class="hljs-attr">X_train=X_train,</span> <span class="hljs-attr">y_train=y_train,</span>
             <span class="hljs-attr">X_test=X_test,</span> <span class="hljs-attr">y_test=y_test,</span>
             <span class="hljs-attr">expression=GROUND_TRUTH_EXPRESSION)</span>

    <span class="hljs-comment"># 保存 CSV</span>
    <span class="hljs-attr">header</span> = <span class="hljs-string">&quot;,&quot;</span>.join(GROUND_TRUTH_SYMBOLS) + <span class="hljs-string">&quot;,y&quot;</span>
    <span class="hljs-attr">rows</span> = np.column_stack([np.vstack([X_train, X_test]),
                            np.hstack([y_train, y_test])])
    <span class="hljs-keyword">with</span> open(out_dir / <span class="hljs-string">&quot;dataset.csv&quot;</span>, <span class="hljs-string">&quot;w&quot;</span>) as f:
        f.write(f<span class="hljs-string">&quot;# 真实公式: {GROUND_TRUTH_EXPRESSION}\n&quot;</span>)
        f.write(f<span class="hljs-string">&quot;# 噪声标准差: {args.noise_std}\n&quot;</span>)
        f.write(header + <span class="hljs-string">&quot;\n&quot;</span>)
        for row <span class="hljs-keyword">in</span> rows:
            f.write(<span class="hljs-string">&quot;,&quot;</span>.join(f<span class="hljs-string">&quot;{v:.8f}&quot;</span> for v <span class="hljs-keyword">in</span> row) + <span class="hljs-string">&quot;\n&quot;</span>)

    print(f<span class="hljs-string">&quot;数据集已保存到 {out_dir}&quot;</span>)


<span class="hljs-keyword">if</span> <span class="hljs-attr">__name__</span> == <span class="hljs-string">&quot;__main__&quot;</span>:
    main()
</code></pre>
<h4 id="-">
	生成的数据样例</h4>
<pre>
<code class="lang-csv"><span class="hljs-selector-tag">x1</span>,<span class="hljs-selector-tag">x2</span>,<span class="hljs-selector-tag">x3</span>,<span class="hljs-selector-tag">x4</span>,<span class="hljs-selector-tag">x5</span>,<span class="hljs-selector-tag">y</span>
<span class="hljs-selector-tag">-0</span><span class="hljs-selector-class">.75275929</span>,2<span class="hljs-selector-class">.70428584</span>,1<span class="hljs-selector-class">.39196365</span>,0<span class="hljs-selector-class">.59195091</span>,<span class="hljs-selector-tag">-2</span><span class="hljs-selector-class">.06388816</span>,<span class="hljs-selector-tag">-0</span><span class="hljs-selector-class">.73060157</span>
<span class="hljs-selector-tag">-2</span><span class="hljs-selector-class">.06403288</span>,<span class="hljs-selector-tag">-2</span><span class="hljs-selector-class">.65149833</span>,2<span class="hljs-selector-class">.19705687</span>,0<span class="hljs-selector-class">.60669007</span>,1<span class="hljs-selector-class">.24843547</span>,4<span class="hljs-selector-class">.13384154</span>
<span class="hljs-selector-tag">-2</span><span class="hljs-selector-class">.87649303</span>,2<span class="hljs-selector-class">.81945911</span>,1<span class="hljs-selector-class">.99465584</span>,<span class="hljs-selector-tag">-1</span><span class="hljs-selector-class">.72596534</span>,<span class="hljs-selector-tag">-1</span><span class="hljs-selector-class">.90905020</span>,<span class="hljs-selector-tag">-2</span><span class="hljs-selector-class">.05631804</span>
<span class="hljs-selector-tag">-1</span><span class="hljs-selector-class">.89957294</span>,<span class="hljs-selector-tag">-1</span><span class="hljs-selector-class">.17454654</span>,0<span class="hljs-selector-class">.14853859</span>,<span class="hljs-selector-tag">-0</span><span class="hljs-selector-class">.40832989</span>,<span class="hljs-selector-tag">-1</span><span class="hljs-selector-class">.25262516</span>,1<span class="hljs-selector-class">.29225609</span>
</code></pre>
<p>
	每行 6 列：x₁ ~ x₅ 为输入，y 为输出。</p>
<p>
	产出文件：</p>
<table>
<thead>
<tr>
<th>
				文件</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<code>datasets/z/dataset.npz</code></td>
<td>
				NumPy 压缩格式，供 <code>from_arrays()</code> 加载</td>
</tr>
<tr>
<td>
				<code>datasets/z/dataset.csv</code></td>
<td>
				CSV 文本格式，肉眼查看用</td>
</tr>
<tr>
<td>
				<code>datasets/z/ground_truth.txt</code></td>
<td>
				真实公式说明</td>
</tr>
<tr>
<td>
				<code>datasets/z/preview.txt</code></td>
<td>
				数据统计摘要</td>
</tr>
</tbody>
</table>
<h3 id="step-2-">
	Step 2：创建临时环境</h3>
<p>
	使用 <code>micromamba</code> 创建独立的 Python 3.12 环境，避免污染已有环境：</p>
<pre>
<code class="lang-bash"><span class="hljs-comment"># 创建</span>
micromamba create -n py312 python=<span class="hljs-number">3</span>.<span class="hljs-number">12</span> -y

<span class="hljs-comment"># 安装依赖</span>
micromamba run -n py312 pip3 <span class="hljs-keyword">install </span><span class="hljs-keyword">scipy </span>sympy <span class="hljs-keyword">scikit-learn </span>h5py \
    tiktoken <span class="hljs-keyword">json-repair </span>cmaes threadpoolctl
</code></pre>
<h3 id="step-3-">
	Step 3：编写测试脚本</h3>
<p>
	保存为 <code>datasets/z/run_test.py</code>：</p>
<pre>
<code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>
<span class="hljs-string">&quot;&quot;</span><span class="hljs-string">&quot;
在 FunctionEvolve 上运行自定义复杂数据集（datasets/z/dataset.npz）的测试脚本。

用法:
  cd /path/to/FunctionEvolve

  # 退化模式（无 LLM，仅验证程序化变异 + 数值优化）
  python datasets/z/run_test.py --degenerated

  # 完整模式（使用 LLM，需要 llm_config.yaml）
  python datasets/z/run_test.py
&quot;</span><span class="hljs-string">&quot;&quot;</span>

<span class="hljs-built_in">import</span> argparse
<span class="hljs-built_in">import</span> os
<span class="hljs-built_in">import</span> sys
from pathlib <span class="hljs-built_in">import</span> Path

<span class="hljs-built_in">import</span> numpy as np

<span class="hljs-attr">PROJECT_ROOT</span> = Path(__file__).resolve().parents[<span class="hljs-number">2</span>]
sys.path.insert(<span class="hljs-number">0</span>, str(PROJECT_ROOT))

from src.dataset <span class="hljs-built_in">import</span> SRDataset
from src.evaluator <span class="hljs-built_in">import</span> Evaluator
from src.evolution_tree <span class="hljs-built_in">import</span> EvolutionTree
from src.search <span class="hljs-built_in">import</span> TreeSearch
from src.generator <span class="hljs-built_in">import</span> MockGenerator, create_generator
from src.selector <span class="hljs-built_in">import</span> MockSelector, create_selector
from src.mutator <span class="hljs-built_in">import</span> MockMutator, LLMMutator
from src.llm_client <span class="hljs-built_in">import</span> build_openai_client, LLMUsageLogger


def _load_dataset(data_dir):
    <span class="hljs-attr">npz_path</span> = data_dir / <span class="hljs-string">&quot;dataset.npz&quot;</span>
    <span class="hljs-attr">data</span> = np.load(npz_path)
    <span class="hljs-attr">expr</span> = str(data[<span class="hljs-string">&quot;expression&quot;</span>].item())
    return SRDataset.from_arrays(
        <span class="hljs-attr">X_train=data[&quot;X_train&quot;],</span> <span class="hljs-attr">y_train=data[&quot;y_train&quot;],</span>
        <span class="hljs-attr">X_test=data[&quot;X_test&quot;],</span> <span class="hljs-attr">y_test=data[&quot;y_test&quot;],</span>
        <span class="hljs-attr">symbols=[&quot;x1&quot;,</span> <span class="hljs-string">&quot;x2&quot;</span>, <span class="hljs-string">&quot;x3&quot;</span>, <span class="hljs-string">&quot;x4&quot;</span>, <span class="hljs-string">&quot;x5&quot;</span>],
        <span class="hljs-attr">symbol_descs=[&quot;v1&quot;,</span> <span class="hljs-string">&quot;v2&quot;</span>, <span class="hljs-string">&quot;v3&quot;</span>, <span class="hljs-string">&quot;v4&quot;</span>, <span class="hljs-string">&quot;v5&quot;</span>],
        <span class="hljs-attr">expression=expr,</span> <span class="hljs-attr">equation_name=&quot;complex_z&quot;,</span>
    )


def _evaluate_ground_truth(ds, evaluator):
    <span class="hljs-string">&quot;&quot;</span><span class="hljs-string">&quot;对真实公式做参数拟合，给出精度天花板。&quot;</span><span class="hljs-string">&quot;&quot;</span>
    <span class="hljs-built_in">import</span> sympy as sp
    <span class="hljs-attr">sympy_expr</span> = sp.sympify(ds.expression)
    <span class="hljs-attr">param_names</span> = sorted(
        {str(s) for s <span class="hljs-keyword">in</span> sympy_expr.free_symbols} - set(ds.feature_names))
    <span class="hljs-attr">result</span> = evaluator.evaluate_skeleton(sympy_expr, param_names)
    print(f<span class="hljs-string">&quot;[Ground Truth] Train NMSE = {result.train_nmse:.2e}&quot;</span>)
    print(f<span class="hljs-string">&quot;[Ground Truth] Test  NMSE = {result.test_nmse:.2e}&quot;</span>)


def main():
    <span class="hljs-attr">parser</span> = argparse.ArgumentParser()
    parser.add_argument(<span class="hljs-string">&quot;--degenerated&quot;</span>, <span class="hljs-attr">action=&quot;store_true&quot;)</span>
    parser.add_argument(<span class="hljs-string">&quot;--max-steps&quot;</span>, <span class="hljs-attr">type=int,</span> <span class="hljs-attr">default=30)</span>
    parser.add_argument(<span class="hljs-string">&quot;--n-seeds&quot;</span>, <span class="hljs-attr">type=int,</span> <span class="hljs-attr">default=20)</span>
    parser.add_argument(<span class="hljs-string">&quot;--candidate-num&quot;</span>, <span class="hljs-attr">type=int,</span> <span class="hljs-attr">default=5)</span>
    parser.add_argument(<span class="hljs-string">&quot;--timeout&quot;</span>, <span class="hljs-attr">type=float,</span> <span class="hljs-attr">default=120.0)</span>
    parser.add_argument(<span class="hljs-string">&quot;--llm-config&quot;</span>, <span class="hljs-attr">type=str,</span> <span class="hljs-attr">default=None)</span>
    parser.add_argument(<span class="hljs-string">&quot;--run-tag&quot;</span>, <span class="hljs-attr">type=str,</span> <span class="hljs-attr">default=&quot;z_test&quot;)</span>
    <span class="hljs-attr">args</span> = parser.parse_args()

    <span class="hljs-attr">data_dir</span> = Path(__file__).resolve().parent
    <span class="hljs-attr">ds</span> = _load_dataset(data_dir)
    print(f<span class="hljs-string">&quot;训练样本: {ds.X_train.shape[0]}, 测试样本: {ds.X_test.shape[0]}&quot;</span>)

    <span class="hljs-attr">evaluator</span> = Evaluator(
        <span class="hljs-attr">feature_names=ds.feature_names,</span> <span class="hljs-attr">X_train=ds.X_train,</span>
        <span class="hljs-attr">y_train=ds.y_train,</span> <span class="hljs-attr">X_test=ds.X_test,</span> <span class="hljs-attr">y_test=ds.y_test,</span>
        <span class="hljs-attr">timeout=args.timeout,</span>
    )
    _evaluate_ground_truth(ds, evaluator)

    <span class="hljs-comment"># 构造 LLM / Mock Agent</span>
    <span class="hljs-attr">llm_config</span> = None
    <span class="hljs-keyword">if</span> not args.degenerated:
        <span class="hljs-attr">cfg_path</span> = args.llm_config <span class="hljs-literal">or</span> str(PROJECT_ROOT / <span class="hljs-string">&quot;llm_config.yaml&quot;</span>)
        <span class="hljs-keyword">if</span> os.path.exists(cfg_path):
            <span class="hljs-built_in">import</span> yaml
            <span class="hljs-keyword">with</span> open(cfg_path) as f:
                <span class="hljs-attr">llm_config</span> = yaml.safe_load(f) <span class="hljs-literal">or</span> {}

    def _resolve(comp, field, <span class="hljs-attr">fallback=None):</span>
        return llm_config.get(comp, {}).get(field, fallback) <span class="hljs-keyword">if</span> llm_config <span class="hljs-keyword">else</span> fallback

    <span class="hljs-keyword">if</span> args.degenerated:
        <span class="hljs-attr">generator</span> = MockGenerator(<span class="hljs-attr">variables=ds.feature_names)</span>
        <span class="hljs-attr">selector</span> = MockSelector(<span class="hljs-attr">variables=ds.feature_names)</span>
        <span class="hljs-attr">llm_mutator</span> = MockMutator()
    <span class="hljs-keyword">else</span>:
        <span class="hljs-attr">gen</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;model&quot;</span>); <span class="hljs-attr">gen_url</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;base_url&quot;</span>)
        <span class="hljs-attr">gen_key</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;api_key&quot;</span>); <span class="hljs-attr">gen_mode</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;mode&quot;</span>, <span class="hljs-string">&quot;openai&quot;</span>)
        <span class="hljs-attr">gen_temp</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;temperature&quot;</span>, <span class="hljs-number">0.8</span>)
        <span class="hljs-attr">gen_tok</span> = _resolve(<span class="hljs-string">&quot;generator&quot;</span>, <span class="hljs-string">&quot;max_tokens&quot;</span>, <span class="hljs-number">128000</span>)
        <span class="hljs-attr">logger</span> = LLMUsageLogger(str(Path(<span class="hljs-string">&quot;logs&quot;</span>) / <span class="hljs-string">&quot;z_custom&quot;</span> / <span class="hljs-string">&quot;llm_usage.csv&quot;</span>))
        <span class="hljs-attr">generator</span> = create_generator(gen, gen_url, gen_key, gen_temp, gen_tok,
                                     <span class="hljs-attr">usage_logger=logger,</span> <span class="hljs-attr">llm_mode=gen_mode)</span>

        <span class="hljs-attr">sm</span> = _resolve(<span class="hljs-string">&quot;selector&quot;</span>, <span class="hljs-string">&quot;model&quot;</span>, gen); <span class="hljs-attr">su</span> = _resolve(<span class="hljs-string">&quot;selector&quot;</span>, <span class="hljs-string">&quot;base_url&quot;</span>, gen_url)
        <span class="hljs-attr">sk</span> = _resolve(<span class="hljs-string">&quot;selector&quot;</span>, <span class="hljs-string">&quot;api_key&quot;</span>, gen_key); <span class="hljs-attr">sd</span> = _resolve(<span class="hljs-string">&quot;selector&quot;</span>, <span class="hljs-string">&quot;mode&quot;</span>, gen_mode)
        <span class="hljs-attr">st</span> = _resolve(<span class="hljs-string">&quot;selector&quot;</span>, <span class="hljs-string">&quot;temperature&quot;</span>, <span class="hljs-number">0.3</span>)
        <span class="hljs-attr">selector</span> = create_selector(sm, su, sk, st, <span class="hljs-attr">usage_logger=logger,</span> <span class="hljs-attr">llm_mode=sd)</span>

        <span class="hljs-attr">mm</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;model&quot;</span>, gen); <span class="hljs-attr">mu</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;base_url&quot;</span>, gen_url)
        <span class="hljs-attr">mk</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;api_key&quot;</span>, gen_key); <span class="hljs-attr">md</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;mode&quot;</span>, gen_mode)
        <span class="hljs-attr">mt</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;temperature&quot;</span>, <span class="hljs-number">0.7</span>)
        <span class="hljs-attr">m_tok</span> = _resolve(<span class="hljs-string">&quot;mutator&quot;</span>, <span class="hljs-string">&quot;max_tokens&quot;</span>, <span class="hljs-number">128000</span>)
        <span class="hljs-attr">client</span> = build_openai_client(mm, mu, <span class="hljs-attr">mode=md,</span> <span class="hljs-attr">api_key=mk)</span>
        <span class="hljs-attr">llm_mutator</span> = LLMMutator(client, mm, mt, m_tok, <span class="hljs-attr">usage_logger=logger)</span>

    <span class="hljs-attr">tree</span> = EvolutionTree()
    <span class="hljs-attr">searcher</span> = TreeSearch(
        <span class="hljs-attr">dataset=ds,</span> <span class="hljs-attr">evaluator=evaluator,</span> <span class="hljs-attr">tree=tree,</span>
        <span class="hljs-attr">selector=selector,</span> <span class="hljs-attr">generator=generator,</span> <span class="hljs-attr">llm_mutator=llm_mutator,</span>
        <span class="hljs-attr">max_steps=args.max_steps,</span> <span class="hljs-attr">n_seeds=args.n_seeds,</span>
        <span class="hljs-attr">candidate_num=args.candidate_num,</span> <span class="hljs-attr">timeout=args.timeout,</span> <span class="hljs-attr">verbose=True,</span>
    )
    searcher.initialize_seeds()
    searcher.run()

    <span class="hljs-comment"># 输出最佳结果</span>
    <span class="hljs-attr">evaluated</span> = [n for n <span class="hljs-keyword">in</span> tree.all_nodes <span class="hljs-keyword">if</span> n.is_evaluated <span class="hljs-literal">and</span> n.train_nmse &lt; float(<span class="hljs-string">&quot;inf&quot;</span>)]
    evaluated.sort(<span class="hljs-attr">key=lambda</span> n: n.train_nmse)
    <span class="hljs-keyword">if</span> evaluated:
        <span class="hljs-attr">best</span> = evaluated[<span class="hljs-number">0</span>]
        print(f<span class="hljs-string">&quot;\n最佳公式: {best.skeleton_str}&quot;</span>)
        print(f<span class="hljs-string">&quot;训练集 NMSE: {best.train_nmse:.4e}&quot;</span>)
        print(f<span class="hljs-string">&quot;测试集 NMSE: {best.test_nmse:.4e}&quot;</span>)


<span class="hljs-keyword">if</span> <span class="hljs-attr">__name__</span> == <span class="hljs-string">&quot;__main__&quot;</span>:
    main()
</code></pre>
<h3 id="step-4-">
	Step 4：运行测试</h3>
<p>
	共运行三个实验：</p>
<p>
	<strong>① 退化模式（1 步）：</strong></p>
<pre>
<code class="lang-bash"><span class="hljs-comment">cd</span> <span class="hljs-comment">/path/to/FunctionEvolve</span>
<span class="hljs-comment">python3</span> <span class="hljs-comment">datasets/z/run_test</span><span class="hljs-string">.</span><span class="hljs-comment">py</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">degenerated</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">max</span><span class="hljs-literal">-</span><span class="hljs-comment">steps</span> <span class="hljs-comment">1</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">n</span><span class="hljs-literal">-</span><span class="hljs-comment">seeds</span> <span class="hljs-comment">3</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">candidate</span><span class="hljs-literal">-</span><span class="hljs-comment">num</span> <span class="hljs-comment">2</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">timeout</span> <span class="hljs-comment">120</span>
</code></pre>
<p>
	<strong>② LLM 模式（1 步）：</strong></p>
<pre>
<code class="lang-bash"><span class="hljs-keyword">cd</span> /path/<span class="hljs-keyword">to</span>/FunctionEvolve
<span class="hljs-keyword">python3</span> datasets/<span class="hljs-keyword">z</span>/run_test.<span class="hljs-keyword">py</span> --<span class="hljs-built_in">max</span>-steps <span class="hljs-number">1</span> --n-seeds <span class="hljs-number">3</span> --candidate-num <span class="hljs-number">2</span> --timeout <span class="hljs-number">120</span>
</code></pre>
<p>
	<strong>③ LLM 模式（3 步）：</strong></p>
<pre>
<code class="lang-bash"><span class="hljs-keyword">cd</span> /path/<span class="hljs-keyword">to</span>/FunctionEvolve
<span class="hljs-keyword">python3</span> datasets/<span class="hljs-keyword">z</span>/run_test.<span class="hljs-keyword">py</span> --<span class="hljs-built_in">max</span>-steps <span class="hljs-number">3</span> --n-seeds <span class="hljs-number">3</span> --candidate-num <span class="hljs-number">2</span> --timeout <span class="hljs-number">120</span>
</code></pre>
<blockquote>
<p>
		为加快运行速度，上述实验使用了 200 训练样本 + 100 测试样本的子集（完整数据集为 2000 + 500）。</p>
</blockquote>
<h3 id="step-5-">
	Step 5：测试输出及分析</h3>
<pre>
<code><span class="hljs-string">[Ground Truth]</span> 训练集 NMSE = <span class="hljs-number">1</span>.77e-<span class="hljs-number">05</span>
<span class="hljs-string">[Ground Truth]</span> 测试集 NMSE = <span class="hljs-number">2</span>.14e-<span class="hljs-number">05</span>
</code></pre>
<p>
	真实公式本身不需要拟合任何参数，NMSE &asymp; 1.8e-5 来自 0.02 标准差的高斯噪声，是本次测试的精度天花板。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h4 id="-a-200-">
	模式 A：退化模式结果（200 样本）</h4>
<p>
	初始种子（退化模式仅基于 x1 生成简易多项式/指数公式）：</p>
<table>
<thead>
<tr>
<th>
				种子公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 x_1 + c_1\)</span><script type='math/tex'>y = c_0 x_1 + c_1</script> </td>
<td>
				0.998</td>
<td>
				0.992</td>
<td>
				线性</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 x_1^2 + c_1 x_1 + c_2\)</span><script type='math/tex'>y = c_0 x_1^2 + c_1 x_1 + c_2</script> </td>
<td>
				0.998</td>
<td>
				0.991</td>
<td>
				二次多项式</td>
</tr>
</tbody>
</table>
<p>
	最优变异后（1 步，2 父本，111 个候选）：</p>
<table>
<thead>
<tr>
<th>
				公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = \frac{c_0 x_1 + c_1}{c_2 e^{c_3 x_2} + 1}\)</span><script type='math/tex'>y = \frac{c_0 x_1 + c_1}{c_2 e^{c_3 x_2} + 1}</script> </td>
<td>
				<strong>0.270</strong></td>
<td>
				<strong>0.319</strong></td>
<td>
				分式 + 指数，引入 x₂</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = (c_0 + c_1 x_1) e^{c_2 x_2}\)</span><script type='math/tex'>y = (c_0 + c_1 x_1) e^{c_2 x_2}</script> </td>
<td>
				0.271</td>
<td>
				0.303</td>
<td>
				线性 &times; 指数</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 x_1 + c_1 + c_2 e^{c_3 x_2}\)</span><script type='math/tex'>y = c_0 x_1 + c_1 + c_2 e^{c_3 x_2}</script> </td>
<td>
				0.283</td>
<td>
				0.344</td>
<td>
				线性 + 指数</td>
</tr>
</tbody>
</table>
<p>
	<strong>退化模式瓶颈</strong>：种子只使用 x1，NMSE approx 1.0；一轮变异后最优 NMSE 0.270（解释 ~73% 方差）。但缺乏 LLM 指引方向，变异盲目枚举（111 个候选中仅少数引入 x2，无法发现 sin 等函数）。</p>
<h4 id="-b-deepseek-200-">
	模式 B：完整模式结果（使用 DeepSeek，200 样本）</h4>
<p>
	<strong>1. LLM Generator 领域分析</strong></p>
<p>
	LLM 成功分析出数据集属于&quot;通用符号回归 / 数学建模&quot;领域，输出了 20+ 个经典公式模式供种子生成参考。</p>
<p>
	<strong>2. LLM 种子生成</strong></p>
<table>
<thead>
<tr>
<th>
				种子公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 + c_1 x_2 + c_2 x_3 + c_3 x_4 + c_4 x_5\)</span><script type='math/tex'>y = c_0 + c_1 x_2 + c_2 x_3 + c_3 x_4 + c_4 x_5</script> </td>
<td>
				~0.89</td>
<td>
				~0.89</td>
<td>
				LLM 尝试全部 5 个变量</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 x_2^{c_1} x_3^{c_2}\)</span><script type='math/tex'>y = c_0 x_2^{c_1} x_3^{c_2}</script> </td>
<td>
				~0.84</td>
<td>
				~0.84</td>
<td>
				LLM 聚焦 x₂, x₃</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4)\)</span><script type='math/tex'>y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4)</script> </td>
<td>
				<strong>~0.35</strong></td>
<td>
				<strong>~0.34</strong></td>
<td>
				LLM 直接猜中 sin + exp 结构！</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 x_2^2 x_3^{c_1}\)</span><script type='math/tex'>y = c_0 x_2^2 x_3^{c_1}</script> （退化兜底）</td>
<td>
				~0.84</td>
<td>
				~0.84</td>
<td>
				&mdash;</td>
</tr>
</tbody>
</table>
<p>
	LLM 的第三个种子 c0<em>exp(c1</em>x2) + c2<em>sin(c3</em>x3 + c4) 已经包含了 <strong>exp + sin</strong>，NMSE 仅 ~0.35，远超退化种子的 ~0.998。</p>
<p>
	<strong>3. LLM Mutator 变异建议</strong></p>
<p>
	LLM 为选中的父本生成了 <strong>20 条定向变异建议</strong>（退化模式中 ASTMutator 靠穷举生成了约 111 条），例如：&quot;尝试多项式展开&quot;、&quot;添加指数衰减项 exp&quot;、&quot;尝试分式结构&quot;、&quot;添加正弦/余弦项&quot;。</p>
<p>
	<strong>4. 各步最优公式</strong></p>
<p>
	LLM 1 步后：</p>
<table>
<thead>
<tr>
<th>
				公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 \sin(c_6 x_4 + c_7)\)</span><script type='math/tex'>y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 \sin(c_6 x_4 + c_7)</script> </td>
<td>
				<strong>0.224</strong></td>
<td>
				<strong>0.300</strong></td>
<td>
				双 sin + exp，引入 x₂~x₄</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 x_4^{c_6}\)</span><script type='math/tex'>y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 x_4^{c_6}</script> </td>
<td>
				0.228</td>
<td>
				0.301</td>
<td>
				幂次替代 sin</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 e^{c_1 x_2} + c_2 x_3 (c_3 + x_1)^{c_4} + c_5 \sin(c_6 x_3 + c_7)\)</span><script type='math/tex'>y = c_0 e^{c_1 x_2} + c_2 x_3 (c_3 + x_1)^{c_4} + c_5 \sin(c_6 x_3 + c_7)</script> </td>
<td>
				0.241</td>
<td>
				0.282</td>
<td>
				引入 x₁</td>
</tr>
</tbody>
</table>
<p>
	LLM 3 步后：</p>
<table>
<thead>
<tr>
<th>
				公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				 <span class='MathJax_Preview'>\(\frac{c_0 x_1 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}\)</span><script type='math/tex'>\frac{c_0 x_1 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}</script> </td>
<td>
				<strong>0.081</strong></td>
<td>
				<strong>0.129</strong></td>
<td>
				复合分式 + sin + exp</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(c_0 x_3 (c_1 + x_1)^{c_2} + c_3 e^{c_4 x_2} + c_5 x_3 e^{c_4 x_2} + c_6 e^{c_4 x_2} \sin(c_7 x_4 + c_8)\)</span><script type='math/tex'>c_0 x_3 (c_1 + x_1)^{c_2} + c_3 e^{c_4 x_2} + c_5 x_3 e^{c_4 x_2} + c_6 e^{c_4 x_2} \sin(c_7 x_4 + c_8)</script> </td>
<td>
				0.088</td>
<td>
				0.110</td>
<td>
				分项式</td>
</tr>
<tr>
<td>
				 <span class='MathJax_Preview'>\(\frac{c_0 x_2 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}\)</span><script type='math/tex'>\frac{c_0 x_2 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}</script> </td>
<td>
				0.099</td>
<td>
				0.157</td>
<td>
				类似结构</td>
</tr>
</tbody>
</table>
<hr />
<p>
	<strong>两种模式找到的最优函数：</strong></p>
<table>
<thead>
<tr>
<th>
				实验</th>
<th>
				最优公式</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				<strong>真实公式</strong></td>
<td>
				 <span class='MathJax_Preview'>\(y = \frac{\sin(x_1 x_2)}{\cos(x_3) + 1.5} + e^{-x_2} \ln(\lvert x_4 \rvert + 1) + \frac{x_1 x_3}{1 + x_5^2}\)</span><script type='math/tex'>y = \frac{\sin(x_1 x_2)}{\cos(x_3) + 1.5} + e^{-x_2} \ln(\lvert x_4 \rvert + 1) + \frac{x_1 x_3}{1 + x_5^2}</script> </td>
<td>
				<strong>1.77e-5</strong></td>
<td>
				<strong>2.14e-5</strong></td>
</tr>
<tr>
<td>
				<strong>退化 1 步</strong></td>
<td>
				 <span class='MathJax_Preview'>\(y = \frac{c_0 x_1 + c_1}{c_2 e^{c_3 x_2} + 1}\)</span><script type='math/tex'>y = \frac{c_0 x_1 + c_1}{c_2 e^{c_3 x_2} + 1}</script> </td>
<td>
				<strong>0.270</strong></td>
<td>
				<strong>0.319</strong></td>
</tr>
<tr>
<td>
				<strong>LLM 1 步</strong></td>
<td>
				 <span class='MathJax_Preview'>\(y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 \sin(c_6 x_4 + c_7)\)</span><script type='math/tex'>y = c_0 e^{c_1 x_2} + c_2 \sin(c_3 x_3 + c_4) + c_5 \sin(c_6 x_4 + c_7)</script> </td>
<td>
				<strong>0.224</strong></td>
<td>
				<strong>0.300</strong></td>
</tr>
<tr>
<td>
				<strong>LLM 3 步</strong></td>
<td>
				 <span class='MathJax_Preview'>\(y = \frac{c_0 x_1 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}\)</span><script type='math/tex'>y = \frac{c_0 x_1 + c_1 + (c_2 x_3 + c_3)(c_4 + c_5 x_3 + c_6 \sin(c_7 x_4 + c_8)) e^{c_9 x_2}}{c_2 x_3 + c_3}</script> </td>
<td>
				<strong>0.081</strong></td>
<td>
				<strong>0.129</strong></td>
</tr>
</tbody>
</table>
<p>
	NMSE 对比（越低越好）：</p>
<table>
<thead>
<tr>
<th>
				模式</th>
<th>
				步数</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				相比退化改善</th>
<th>
				关键发现</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				真实公式</td>
<td>
				--</td>
<td>
				1.77e-5</td>
<td>
				2.14e-5</td>
<td>
				--</td>
<td>
				精度天花板</td>
</tr>
<tr>
<td>
				退化</td>
<td>
				1 步</td>
<td>
				0.270</td>
<td>
				0.319</td>
<td>
				基准</td>
<td>
				分式 + 指数（x₁, x₂）</td>
</tr>
<tr>
<td>
				LLM</td>
<td>
				1 步</td>
<td>
				<strong>0.224</strong></td>
<td>
				<strong>0.300</strong></td>
<td>
				&darr; 17%</td>
<td>
				发现 <strong>sin()</strong>，引入 x₃, x₄</td>
</tr>
<tr>
<td>
				LLM</td>
<td>
				<strong>3 步</strong></td>
<td>
				<strong>0.081</strong></td>
<td>
				<strong>0.129</strong></td>
<td>
				<strong>&darr; 70%</strong></td>
<td>
				复合分式 + sin + exp（x₁~x₄）</td>
</tr>
</tbody>
</table>
<blockquote>
<p>
		LLM 1 步内就发现了退化模式无法找到的 <strong>sin()</strong>。3 步后 NMSE 降到 <strong>0.081</strong>（解释 ~92% 方差），但 x₁&times;x₂ 的 sin 交互和 x₅ 尚未被完整识别。预计 LLM 模式 5~10 步可收敛到 NMSE &lt; 1e-3。</p>
</blockquote>
<h4 id="-">
	当前进度与收敛预估</h4>
<table>
<thead>
<tr>
<th>
				维度</th>
<th>
				值</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				变量数</td>
<td>
				5（x₁~x₅）</td>
</tr>
<tr>
<td>
				函数种类</td>
<td>
				sin, cos, exp, log, 除法（5 种）</td>
</tr>
<tr>
<td>
				交互关系</td>
<td>
				x₁&times;x₂, x₁&times;x₃, x₂（指数项）, x₄（对数项）, x₅（分式）</td>
</tr>
<tr>
<td>
				噪声</td>
<td>
				0.02 标准差</td>
</tr>
</tbody>
</table>
<p>
	当前实验进度（基于 200 训练样本 + 100 测试样本）：</p>
<table>
<thead>
<tr>
<th>
				实验</th>
<th>
				训练集 NMSE</th>
<th>
				测试集 NMSE</th>
<th>
				关键发现</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				退化 1 步</td>
<td>
				0.270</td>
<td>
				0.319</td>
<td>
				分式 + 指数，仅 x₁, x₂</td>
</tr>
<tr>
<td>
				LLM 1 步</td>
<td>
				0.224</td>
<td>
				0.300</td>
<td>
				发现 <strong>sin()</strong>，引入 x₃, x₄</td>
</tr>
<tr>
<td>
				LLM <strong>3 步</strong></td>
<td>
				<strong>0.081</strong></td>
<td>
				<strong>0.129</strong></td>
<td>
				复合分式 + sin + exp，引入 x₁~x₄</td>
</tr>
</tbody>
</table>
<p>
	LLM 3 步后 NMSE 0.081（解释 ~92% 方差），已成功发现 sin() 函数并引入了 x₁~x₄ 四个变量。但真实公式中 x₁&times;x₂ 的 sin 交互、x₁&times;x₃ 的分式交互以及 x₅ 的分式尚未被完整识别。预计：</p>
<ul>
<li>
		<strong>LLM 模式</strong>：5~10 步可收敛到 NMSE &lt; 1e-3</li>
<li>
		<strong>退化模式</strong>：相同步数下 NMSE 下降仅 ~18%/步，效率远低于 LLM</li>
</ul>
<p>
	这正是 FunctionEvolve 采用 LLM + 数值优化混合架构的原因&mdash;&mdash;<strong>LLM 提供方向，数值优化负责精确拟合</strong>。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<h3 id="step-6-">
	Step 6：清理临时环境</h3>
<pre>
<code class="lang-bash"><span class="hljs-comment"># 测试完成后删除临时环境</span>
<span class="hljs-attribute">micromamba</span> remove -n py312 --<span class="hljs-literal">all</span> -y
</code></pre>
<h3 id="-">
	总结</h3>
<table>
<thead>
<tr>
<th>
				项目</th>
<th>
				状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>
				测试数据集生成</td>
<td>
				完成</td>
</tr>
<tr>
<td>
				测试脚本</td>
<td>
				完成（<code>datasets/z/run_test.py</code>）</td>
</tr>
<tr>
<td>
				退化模式（1 步）</td>
<td>
				完成（NMSE 0.270 / 0.319，无 LLM）</td>
</tr>
<tr>
<td>
				LLM 模式（1 步）</td>
<td>
				完成（NMSE 0.224 / 0.300，发现 sin()）</td>
</tr>
<tr>
<td>
				<strong>LLM 模式（3 步）</strong></td>
<td>
				<strong>完成（NMSE 0.081 / 0.129，解释 ~92% 方差）</strong></td>
</tr>
<tr>
<td>
				搜索正确性验证</td>
<td>
				全流程无错误，所有实验数据完整记录</td>
</tr>
<tr>
<td>
				临时环境清理</td>
<td>
				已删除</td>
</tr>
</tbody>
</table>
<p>
	<strong>结论</strong>：FunctionEvolve 的搜索管道可以正常运行。LLM 模式显著优于退化模式&mdash;&mdash;1 步即可发现退化模式无法找到的 sin() 函数，3 步后 NMSE 降至 <strong>0.081</strong>。其实上面的测试还没有找到最终的正确公式，由于我电脑性能不强，仅仅运行上面的测试就已经花了很长时间+风扇狂转，因此测试只能止步于此。但可以看到，FunctionEvolve相较于传统优化方法是有较大优势的。</p>
<p>	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span> 版权声明 <span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%bb%93%e5%90%88%e5%a4%a7%e6%a8%a1%e5%9e%8bllm%e7%9a%84%e5%87%bd%e6%95%b0%e6%90%9c%e7%b4%a2%e5%99%a8-functionevolve-%e7%ae%80%e5%8d%95%e5%ae%9e%e6%b5%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>批量复制历史日期的Hive表</title>
		<link>https://www.codelast.com/%e6%89%b9%e9%87%8f%e5%a4%8d%e5%88%b6%e5%8e%86%e5%8f%b2%e6%97%a5%e6%9c%9f%e7%9a%84hive%e8%a1%a8/</link>
					<comments>https://www.codelast.com/%e6%89%b9%e9%87%8f%e5%a4%8d%e5%88%b6%e5%8e%86%e5%8f%b2%e6%97%a5%e6%9c%9f%e7%9a%84hive%e8%a1%a8/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 09:49:41 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[复制Hive表]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14221</guid>

					<description><![CDATA[<p>如果Hive表的分区是日期，并且每天数据不大，那么如果想批量把某一天的数据复制出多天的数据，最快的方法可能是直接复制磁盘文件，然后再用一行命令处理一下即可。<br />
<span id="more-14221"></span><br />
（1）先找到Hive表所在的HDFS目录，假设我们想用 2026-03-20 的数据复制出 2026-03-21 的数据，则：</p>
<blockquote>
<p>
		hadoop fs -cp /path/to/your/hive/table/hdfs/dir/date=2026-03-20&#160;/path/to/your/hive/table/hdfs/dir/date=2026-03-21</p>
</blockquote>
<p>（2）光复制目录没用，数据仍然是查询不到的，需要用在Hive命令行交互模式下，执行以下命令让复制出来的数据&#34;生效&#34;</p>
<blockquote>
<p>
		msck repair table 表名;</p>
</blockquote>
<p>该命令用于修复表的元数据。<br />
直接在 HDFS 上创建了分区目录，但未通过 ALTER TABLE ADD PARTITION 命令注册到 Hive 元数据中，运行msck命令后，这些分区会被自动发现并添加到元数据。&#8230; <a href="https://www.codelast.com/%e6%89%b9%e9%87%8f%e5%a4%8d%e5%88%b6%e5%8e%86%e5%8f%b2%e6%97%a5%e6%9c%9f%e7%9a%84hive%e8%a1%a8/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>如果Hive表的分区是日期，并且每天数据不大，那么如果想批量把某一天的数据复制出多天的数据，最快的方法可能是直接复制磁盘文件，然后再用一行命令处理一下即可。<br />
<span id="more-14221"></span><br />
（1）先找到Hive表所在的HDFS目录，假设我们想用 2026-03-20 的数据复制出 2026-03-21 的数据，则：</p>
<blockquote>
<p>
		hadoop fs -cp /path/to/your/hive/table/hdfs/dir/date=2026-03-20&nbsp;/path/to/your/hive/table/hdfs/dir/date=2026-03-21</p>
</blockquote>
<p>（2）光复制目录没用，数据仍然是查询不到的，需要用在Hive命令行交互模式下，执行以下命令让复制出来的数据&quot;生效&quot;</p>
<blockquote>
<p>
		msck repair table 表名;</p>
</blockquote>
<p>该命令用于修复表的元数据。<br />
直接在 HDFS 上创建了分区目录，但未通过 ALTER TABLE ADD PARTITION 命令注册到 Hive 元数据中，运行msck命令后，这些分区会被自动发现并添加到元数据。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e6%89%b9%e9%87%8f%e5%a4%8d%e5%88%b6%e5%8e%86%e5%8f%b2%e6%97%a5%e6%9c%9f%e7%9a%84hive%e8%a1%a8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 美化git diff命令在终端的显示效果</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%be%8e%e5%8c%96git-diff%e5%91%bd%e4%bb%a4%e5%9c%a8%e7%bb%88%e7%ab%af%e7%9a%84%e6%98%be%e7%a4%ba%e6%95%88%e6%9e%9c/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%be%8e%e5%8c%96git-diff%e5%91%bd%e4%bb%a4%e5%9c%a8%e7%bb%88%e7%ab%af%e7%9a%84%e6%98%be%e7%a4%ba%e6%95%88%e6%9e%9c/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 09 Mar 2026 03:20:04 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[git diff]]></category>
		<category><![CDATA[git-delta]]></category>
		<category><![CDATA[左右双屏]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14209</guid>

					<description><![CDATA[<p>本文适用的环境：<br />
MacOS、Ubuntu（仅在20.04.6 LTS上做了测试）<br />
git diff命令在终端执行时，其显示效果是：<br />
* 按文件分块：每个有改动的文件单独一段，从上到下依次展示。<br />
* 统一在一个终端窗口内纵向滚动，默认不会并排显示左右对比。<br />
我个人觉得，这种显示方式，不如&#34;左右对比&#34;的diff形式直观。<br />
所以，有没有办法把git diff命令的输出，改造成更美观的形式呢？<br />
<span id="more-14209"></span><br />
在MacOS下，可以安装 git-delta，再稍加配置，就可以让终端里的 git diff&#160;命令显式美观得多。<br />
先看最终效果：<br />
<img decoding="async" alt="git diff" src="https://www.codelast.com/wp-content/uploads/2026/03/git_diff_style_change.jpg" style="width: 700px; height: 259px;" /><br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<p>这个效果是怎么实现的呢？按如下步骤操作&#8212;&#8212;<br />
以MacOS为例，安装：</p>
<blockquote>
<p>
		brew install git-delta</p>
</blockquote>
<p>全局配置到git，修改 ~/.gitconfig&#160;文件，添加如下内容：</p>
<blockquote>
<div>
		[core]</div>
<div>
		&#160; &#160; pager = delta</div>
<div>
		[interactive]</div>
<div>
		&#160; &#160; diffFilter = delta --color-only</div>
<div>
		[delta]</div>
<div>
		&#160; &#160; syntax-theme = Monokai Extended</div>
<div>
		&#160; &#160; line-numbers = true</div>
<div>
		&#160; &#160; side-by-side = true</div>
</blockquote>
<div>
	各配置项含义如下：
<div class="document">
<div class="section">
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[core] pager = delta</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">把 Git 的&#8220;分页器&#8221;改成 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">delta</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">影响的命令：如 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git diff</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">、</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git log -p</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;"> 等需要分页显示的输出</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">作用：这些命令的输出不再通过 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">less</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">，而是先经过 delta 进行美化后再显示</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[interactive] diffFilter = delta --color-only</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">专门给交互式操作（如 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git add -p</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">）设置 diff 过滤器</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">Git 在交互式展示每一块 diff 时，先把原始 diff 丢给 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">delta --color-only</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">-color-only</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">：只加颜色高亮，不改行号、不改文本结构，确保交互命令正常工作</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] syntax-theme = Monokai Extended</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">设置 delta 的语法高亮主题为 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">Monokai Extended</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">影响代码内容的配色风格（关键字、字符串、注释等的颜色方案）</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] line-numbers = true</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">在 delta 输出中展示行号</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">一般会在左侧或边栏显示老/新文件的行号，方便定位</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] side-by-side = true</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">使用左右并排对比模式显示 diff</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &#34;Times New Roman&#34;;">&#160;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">左侧通常是旧版本，右侧是新版本，效果类似 GitHub PR 的对比视图</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
</div>
</div>
<p>
	其中，你可以用&#160;delta --list-syntax-themes&#160;命令查看所有内置主题，并设置到 syntax-theme&#160;配置项中。</p>
<p>	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%be%8e%e5%8c%96git-diff%e5%91%bd%e4%bb%a4%e5%9c%a8%e7%bb%88%e7%ab%af%e7%9a%84%e6%98%be%e7%a4%ba%e6%95%88%e6%9e%9c/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>本文适用的环境：<br />
MacOS、Ubuntu（仅在20.04.6 LTS上做了测试）<br />
git diff命令在终端执行时，其显示效果是：<br />
* 按文件分块：每个有改动的文件单独一段，从上到下依次展示。<br />
* 统一在一个终端窗口内纵向滚动，默认不会并排显示左右对比。<br />
我个人觉得，这种显示方式，不如&quot;左右对比&quot;的diff形式直观。<br />
所以，有没有办法把git diff命令的输出，改造成更美观的形式呢？<br />
<span id="more-14209"></span><br />
在MacOS下，可以安装 git-delta，再稍加配置，就可以让终端里的 git diff&nbsp;命令显式美观得多。<br />
先看最终效果：<br />
<img decoding="async" alt="git diff" src="https://www.codelast.com/wp-content/uploads/2026/03/git_diff_style_change.jpg" style="width: 700px; height: 259px;" /><br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<p>这个效果是怎么实现的呢？按如下步骤操作&mdash;&mdash;<br />
以MacOS为例，安装：</p>
<blockquote>
<p>
		brew install git-delta</p>
</blockquote>
<p>全局配置到git，修改 ~/.gitconfig&nbsp;文件，添加如下内容：</p>
<blockquote>
<div>
		[core]</div>
<div>
		&nbsp; &nbsp; pager = delta</div>
<div>
		[interactive]</div>
<div>
		&nbsp; &nbsp; diffFilter = delta --color-only</div>
<div>
		[delta]</div>
<div>
		&nbsp; &nbsp; syntax-theme = Monokai Extended</div>
<div>
		&nbsp; &nbsp; line-numbers = true</div>
<div>
		&nbsp; &nbsp; side-by-side = true</div>
</blockquote>
<div>
	各配置项含义如下：</p>
<div class="document">
<div class="section">
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[core] pager = delta</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">把 Git 的&ldquo;分页器&rdquo;改成 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">delta</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">影响的命令：如 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git diff</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">、</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git log -p</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;"> 等需要分页显示的输出</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">作用：这些命令的输出不再通过 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">less</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">，而是先经过 delta 进行美化后再显示</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[interactive] diffFilter = delta --color-only</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">专门给交互式操作（如 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">git add -p</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">）设置 diff 过滤器</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">Git 在交互式展示每一块 diff 时，先把原始 diff 丢给 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">delta --color-only</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">-color-only</span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">：只加颜色高亮，不改行号、不改文本结构，确保交互命令正常工作</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] syntax-theme = Monokai Extended</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">设置 delta 的语法高亮主题为 </span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">Monokai Extended</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">影响代码内容的配色风格（关键字、字符串、注释等的颜色方案）</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] line-numbers = true</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">在 delta 输出中展示行号</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">一般会在左侧或边栏显示老/新文件的行号，方便定位</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt; font-size: 12pt; text-align: justify; font-family: 等线;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">●<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; font-weight: bold; letter-spacing: 0pt; vertical-align: baseline;">[delta] side-by-side = true</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">使用左右并排对比模式显示 diff</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
<p class="paragraph text-align-type-justify MsoNormal" style="margin: 3pt 0pt 3pt 3.52727em; font-size: 12pt; text-align: justify; font-family: 等线; text-indent: -16.8pt;">
				<span style="font-family: Wingdings;"><span style="font-size: 11pt; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;">○<span style="font-family: &quot;Times New Roman&quot;;">&nbsp;</span></span></span><span data-font-family="微软雅黑" style="font-size: 11pt; font-family: 微软雅黑; letter-spacing: 0pt; vertical-align: baseline;">左侧通常是旧版本，右侧是新版本，效果类似 GitHub PR 的对比视图</span><span lang="EN-US" style="font-size: 11pt; font-family: 微软雅黑; color: rgb(51, 51, 51); letter-spacing: 0pt; vertical-align: baseline;"><o:p></o:p></span></p>
</p></div>
</p></div>
<p>
	其中，你可以用&nbsp;delta --list-syntax-themes&nbsp;命令查看所有内置主题，并设置到 syntax-theme&nbsp;配置项中。</p>
<p>	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
<div>
		&nbsp;</div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%be%8e%e5%8c%96git-diff%e5%91%bd%e4%bb%a4%e5%9c%a8%e7%bb%88%e7%ab%af%e7%9a%84%e6%98%be%e7%a4%ba%e6%95%88%e6%9e%9c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 用Whisper.cpp在本地(离线)把mp3音频转成中文</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%94%a8whisper-cpp%e5%9c%a8%e6%9c%ac%e5%9c%b0%e7%a6%bb%e7%ba%bf%e6%8a%8amp3%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%88%90%e4%b8%ad%e6%96%87/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%94%a8whisper-cpp%e5%9c%a8%e6%9c%ac%e5%9c%b0%e7%a6%bb%e7%ba%bf%e6%8a%8amp3%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%88%90%e4%b8%ad%e6%96%87/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 17 Sep 2025 14:29:50 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[ASR]]></category>
		<category><![CDATA[mp3转中文]]></category>
		<category><![CDATA[OpenAI]]></category>
		<category><![CDATA[whisper.cpp]]></category>
		<category><![CDATA[Whisper模型]]></category>
		<category><![CDATA[语音识别]]></category>
		<category><![CDATA[语音转文字]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14183</guid>

					<description><![CDATA[<p>如果你有把mp3音频转成中文文本、并且不想调用任何云端API的需求，那么本文提供了一个可行的方案。<br />
OS：Ubuntu 20.04 LTS（MacOS类似可用）<br />
<span id="more-14183"></span></p>
<div style="text-align: center;">
	<img decoding="async" alt="audio to text" src="https://www.codelast.com/wp-content/uploads/2025/09/audio_to_text.png" style="width: 600px; height: 528px;" /></div>
<p>
我们首先要知道几个背景知识：<br />
<span style="color:#ff0000;">➤</span> whisper.cpp 是一个开源的 C/C++ 实现，用于运行 OpenAI 的 Whisper 模型。Whisper 是一种先进的自动语音识别（Automatic Speech Recognition, ASR）神经网络模型，能够将音频转换为文本。它支持多种语言，识别效果精准，并且可以完全离线运行，无需互联网连接。这个项目特别适合嵌入到各种应用程序中，因为它是轻量级的实现，可以在 CPU 上高效运行。<br />
<span style="color: rgb(255, 0, 0);">➤</span>&#160;whisper.cpp-cli 是对 whisper.cpp 命令行工具的 Python 封装。<br />
<span style="color:#ff0000;">➤</span>&#160;OpenAI 的 Whisper 模型是一个先进的自动语音识别系统。它是基于 Transformer 架构的神经网络模型，主要用于将音频转换为文本。Whisper 由 OpenAI 开源开发，使用了大规模的多语言数据集进行训练（包括 68 万小时的音频数据，支持 98 种语言），因此具有出色的准确性和鲁棒性，能够处理多种口音、背景噪音和技术术语。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%94%a8whisper-cpp%e5%9c%a8%e6%9c%ac%e5%9c%b0%e7%a6%bb%e7%ba%bf%e6%8a%8amp3%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%88%90%e4%b8%ad%e6%96%87/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>如果你有把mp3音频转成中文文本、并且不想调用任何云端API的需求，那么本文提供了一个可行的方案。<br />
OS：Ubuntu 20.04 LTS（MacOS类似可用）<br />
<span id="more-14183"></span></p>
<div style="text-align: center;">
	<img decoding="async" alt="audio to text" src="https://www.codelast.com/wp-content/uploads/2025/09/audio_to_text.png" style="width: 600px; height: 528px;" /></div>
<p>
我们首先要知道几个背景知识：<br />
<span style="color:#ff0000;">➤</span> whisper.cpp 是一个开源的 C/C++ 实现，用于运行 OpenAI 的 Whisper 模型。Whisper 是一种先进的自动语音识别（Automatic Speech Recognition, ASR）神经网络模型，能够将音频转换为文本。它支持多种语言，识别效果精准，并且可以完全离线运行，无需互联网连接。这个项目特别适合嵌入到各种应用程序中，因为它是轻量级的实现，可以在 CPU 上高效运行。<br />
<span style="color: rgb(255, 0, 0);">➤</span>&nbsp;whisper.cpp-cli 是对 whisper.cpp 命令行工具的 Python 封装。<br />
<span style="color:#ff0000;">➤</span>&nbsp;OpenAI 的 Whisper 模型是一个先进的自动语音识别系统。它是基于 Transformer 架构的神经网络模型，主要用于将音频转换为文本。Whisper 由 OpenAI 开源开发，使用了大规模的多语言数据集进行训练（包括 68 万小时的音频数据，支持 98 种语言），因此具有出色的准确性和鲁棒性，能够处理多种口音、背景噪音和技术术语。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
因此，我们需要安装的是 <a href="https://github.com/charliermarsh/whisper.cpp-cli" target="_blank">whisper.cpp-cli</a>，并且要下载好 Whisper 模型文件，这样就能使用 whisper.cpp-cli 来调用Whisper模型文件进行语音识别了。<br />
为了不影响系统里安装的软件，我们通常都会用micromamba、uv之类的Python包管理器创建一个新的env（环境），然后在里面再安装其他的Python包。这里我们用uv，你也可以用其他的包管理器来创建env。</p>
<blockquote>
<p>
		mkdir whisper<br />
		cd whisper<br />
		uv venv . --python 3.8&nbsp; # 创建一个新环境<br />
		source&nbsp;bin/activate&nbsp; # 激活环境<br />
		uv pip install pip&nbsp; # 安装pip<br />
		pip install whisper.cpp-cli&nbsp; # 安装whisper.cpp-cli</p>
</blockquote>
<p>
这样我们就安装好了相关软件。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
把 mp3 转成 16 kHz 的 wav 文件：</p>
<blockquote>
<p>
		ffmpeg -y -i /home/codelast/st.mp3 -ar 16000 /home/codelast/st.wav</p>
</blockquote>
<p>注意，16 kHz 是Whisper要求的。</p>
<p>然后我们就可以开始做语音识别了：</p>
<blockquote>
<p>
		&nbsp;whisper-cpp -m ../whisper.cpp/download/x-ggml-model.zh.bin -f /home/codelast/st.wav -l zh --output-txt</p>
</blockquote>
<p>这个命令的参数：<br />
-m：指定使用 x-ggml-model.zh.bin 这个模型来做语音识别（模型文件要提前从 Hugging Face 上下载好）<br />
-f：指定输入文件，对 st.wav 这个音频文件进行语音识别<br />
-l：指定输出语言为中文<br />
--output-txt：直接输出txt文本。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
输出内容示例如下：</p>
<blockquote>
<div>
		whisper_init_from_file_with_params_no_state: loading model from &#39;../whisper.cpp/download/x-ggml-model.zh.bin&#39;</div>
<div>
		whisper_model_load: loading model</div>
<div>
		whisper_model_load: n_vocab&nbsp; &nbsp; &nbsp; &nbsp;= 51865</div>
<div>
		whisper_model_load: n_audio_ctx&nbsp; &nbsp;= 1500</div>
<div>
		whisper_model_load: n_audio_state = 768</div>
<div>
		whisper_model_load: n_audio_head&nbsp; = 12</div>
<div>
		whisper_model_load: n_audio_layer = 12</div>
<div>
		whisper_model_load: n_text_ctx&nbsp; &nbsp; = 448</div>
<div>
		whisper_model_load: n_text_state&nbsp; = 768</div>
<div>
		whisper_model_load: n_text_head&nbsp; &nbsp;= 12</div>
<div>
		whisper_model_load: n_text_layer&nbsp; = 12</div>
<div>
		whisper_model_load: n_mels&nbsp; &nbsp; &nbsp; &nbsp; = 80</div>
<div>
		whisper_model_load: ftype&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 1</div>
<div>
		whisper_model_load: qntvr&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 0</div>
<div>
		whisper_model_load: type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = 3 (small)</div>
<div>
		whisper_model_load: adding 1608 extra tokens</div>
<div>
		whisper_model_load: n_langs&nbsp; &nbsp; &nbsp; &nbsp;= 99</div>
<div>
		whisper_model_load:&nbsp; &nbsp; &nbsp; CPU total size =&nbsp; &nbsp;487.01 MB</div>
<div>
		whisper_model_load: model size&nbsp; &nbsp; =&nbsp; 487.01 MB</div>
<div>
		whisper_init_state: kv self size&nbsp; =&nbsp; &nbsp;49.55 MB</div>
<div>
		whisper_init_state: kv cross size =&nbsp; &nbsp;55.30 MB</div>
<div>
		whisper_init_state: compute buffer (conv)&nbsp; &nbsp;=&nbsp; &nbsp;22.54 MB</div>
<div>
		&nbsp;whisper_init_state: compute buffer (encode) =&nbsp; 2&nbsp;80.20 MB</div>
<div>
		whisper_init_state: compute buffer (cross)&nbsp; =&nbsp; &nbsp; 6.31 MB</div>
<div>
		whisper_init_state: compute buffer (decode) =&nbsp; &nbsp;97.40 MB</div>
<div>
		&nbsp;</div>
<div>
		system_info: n_threads = 4 / 8 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | METAL = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 | CUDA = 0 | COREML = 0 | OPENVINO = 0</div>
<div>
		&nbsp;</div>
<div>
		main: processing &#39;/home/codelast/st.wav&#39; (23957094 samples, 1497.3 sec), 4 threads, 1 processors, 5 beams + best of 5, lang = zh, task = transcribe, timestamps = 1 ...</div>
<div>
		&nbsp;</div>
<div>
		&nbsp;</div>
<div>
		[00:00:00.000 --&gt; 00:00:19.040]&nbsp; 这里是识别文字第一句</div>
<div>
		[00:00:19.040 --&gt; 00:00:40.280]&nbsp; 这里是识别文字第二句<br />
		......</div>
</blockquote>
<div>
	<br />
	可以看到，输出的内容是带有时间轴标识的。<br />
	细看会发现，Whisper输出的中文有时会有错别字，我们可以用AI进一步纠错，想怎么处理你就可以随意发挥了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
<div>
		&nbsp;</div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e7%94%a8whisper-cpp%e5%9c%a8%e6%9c%ac%e5%9c%b0%e7%a6%bb%e7%ba%bf%e6%8a%8amp3%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%88%90%e4%b8%ad%e6%96%87/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 如何判断已经启动的TF-Serving服务是否正在使用</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 16 Sep 2024 04:27:03 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[TF-Serving]]></category>
		<category><![CDATA[TFServing]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14136</guid>

					<description><![CDATA[<p>在一台服务器上，如果启动了一个TF-Serving服务，我们知道它占了资源，却不知道它是在空跑还是<span style="color:#ff0000;">真的在用</span>。<br />
本文描述了怎样判断它是否真的在用。<br />
<span id="more-14136"></span></p>
<div>
	用 nvidia-smi 命令能看到 TF-Serving 服务在运行：</div>
<p><img decoding="async" alt="TF-Serving is running" src="https://www.codelast.com/wp-content/uploads/2024/09/tf_serving_running.png" style="width: 700px; height: 149px;" /></p>
<div>
<div>
		其进程id是 22871，于是进一步查询这个进程的信息：</div>
<blockquote>
<div>
			ps -ef &#124; grep 22871</div>
</blockquote>
<div>
		输出类似于：</div>
<blockquote>
<div>
			root&#160; &#160; &#160;22871 22729 83 13:42 pts/0&#160; &#160; 00:06:35 tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=codelast --model_base_path=/models/codelast</div>
</blockquote>
<div>
		可见其REST服务的端口号为 8501。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>
<div>
			于是我们可以用 tcpdump 来捕获并分析流量，运行以下命令(需要 root 权限)：：</div>
<blockquote>
<div>
				sudo tcpdump -vv -i any &#39;port 8501&#39;</div>
</blockquote>
<div>
			如果有客户端正在向这个TF-Serving服务发送请求，我们应会看到这个命令有输出，不断在刷屏，类似于：
<div>
				<span style="color:#0000ff;">14:27:59.174425 IP (tos 0x0, ttl 60, id 51707, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.60679</span></div></div></div></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>在一台服务器上，如果启动了一个TF-Serving服务，我们知道它占了资源，却不知道它是在空跑还是<span style="color:#ff0000;">真的在用</span>。<br />
本文描述了怎样判断它是否真的在用。<br />
<span id="more-14136"></span></p>
<div>
	用 nvidia-smi 命令能看到 TF-Serving 服务在运行：</div>
<p><img decoding="async" alt="TF-Serving is running" src="https://www.codelast.com/wp-content/uploads/2024/09/tf_serving_running.png" style="width: 700px; height: 149px;" /></p>
<div>
<div>
		其进程id是 22871，于是进一步查询这个进程的信息：</div>
<blockquote>
<div>
			ps -ef | grep 22871</div>
</blockquote>
<div>
		输出类似于：</div>
<blockquote>
<div>
			root&nbsp; &nbsp; &nbsp;22871 22729 83 13:42 pts/0&nbsp; &nbsp; 00:06:35 tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=codelast --model_base_path=/models/codelast</div>
</blockquote>
<div>
		可见其REST服务的端口号为 8501。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<div>
			于是我们可以用 tcpdump 来捕获并分析流量，运行以下命令(需要 root 权限)：：</div>
<blockquote>
<div>
				sudo tcpdump -vv -i any &#39;port 8501&#39;</div>
</blockquote>
<div>
			如果有客户端正在向这个TF-Serving服务发送请求，我们应会看到这个命令有输出，不断在刷屏，类似于：</p>
<div>
				<span style="color:#0000ff;">14:27:59.174425 IP (tos 0x0, ttl 60, id 51707, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.60679 &gt; 172.17.0.2.cmtp-mgt: Flags [.], cksum 0x310f (correct), seq 617580:619040, ack 1, win 63, length 1460</span></div>
<div>
				<span style="color:#0000ff;">14:27:59.174453 IP (tos 0x0, ttl 60, id 39347, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.32739 &gt; 172.17.0.2.cmtp-mgt: Flags [.], cksum 0x9354 (correct), seq 44268904:44270364, ack 1, win 86, length 1460</span></div>
<p>			如果没有请求发到TF-Serving服务，那么上面的命令什么都不会输出，就表明TF-Serving服务没在用。<br />
			<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
			<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
			转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
			感谢关注我的微信公众号（微信扫一扫）：<br />
			<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
			以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
				<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</p></div>
<p>
		&nbsp;</div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] JAVA map-reduce job的counter页面无法显示的问题(error 500)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e7%9a%84counter%e9%a1%b5%e9%9d%a2%e6%97%a0%e6%b3%95%e6%98%be%e7%a4%ba%e7%9a%84%e9%97%ae%e9%a2%98error-500/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e7%9a%84counter%e9%a1%b5%e9%9d%a2%e6%97%a0%e6%b3%95%e6%98%be%e7%a4%ba%e7%9a%84%e9%97%ae%e9%a2%98error-500/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Tue, 30 Apr 2024 09:11:34 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[error 500]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[map-reduce]]></category>
		<category><![CDATA[RFC 2616]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14101</guid>

					<description><![CDATA[<p>这个问题已经不是第一次遇到了，只不过今天痛下决心花费不少时间把它写成文章，给遇到同样问题的朋友一些参考。<br />
我们知道，一个JAVA M-R job跑完后，无论是在命令行，还是在job的信息展示网页上，都会看到输出job counter的信息。在网页上，通过点击job信息页中的&#34;counter&#34;链接就能看到。<br />
<span id="more-14101"></span><br />
<img decoding="async" alt="hadoop job info page" src="https://www.codelast.com/wp-content/uploads/2024/04/hadoop_job_info_page.png" style="width: 339px; height: 361px;" /></p>
<p>本来嘛，点进这个页面，会看到正常的counter数据，但是，出问题的情况下，点进去看到的是这种情况：<br />
<img decoding="async" alt="hadoop counter info error" src="https://www.codelast.com/wp-content/uploads/2024/04/hadoop_counter_error.png" style="width: 561px; height: 144px;" /><br />
同时，在shell命令行你也会发现，该job没有任何counter信息输出。<br />
从错误信息页上，你得不到关于错误的任何有效信息，那个&#34;Error Details&#34;里也没有。<br />
虽然counter无法显示，但M-R job是可以正常跑完、正常输出数据的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
经过测试，我这个case的的问题是：在程序中添加了数量比较多的Hadoop counter造成的。<br />
什么算多？我不知道。我的程序里有240多个counter就出问题了，当我把counter缩减了一半，最终只有120多个counter的时候，counter信息统计就正常了。<br />
如果你遇到了类似问题，可以首先检查一下job中的counter数量是否太多。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&#160;版权声明&#160;<span style="color: rgb(255, 0, 0);">➤➤</span>&#160;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&#160;<br />
感谢关注我的微信公众号（微信扫一扫）：<br />
<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" />&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e7%9a%84counter%e9%a1%b5%e9%9d%a2%e6%97%a0%e6%b3%95%e6%98%be%e7%a4%ba%e7%9a%84%e9%97%ae%e9%a2%98error-500/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>这个问题已经不是第一次遇到了，只不过今天痛下决心花费不少时间把它写成文章，给遇到同样问题的朋友一些参考。<br />
我们知道，一个JAVA M-R job跑完后，无论是在命令行，还是在job的信息展示网页上，都会看到输出job counter的信息。在网页上，通过点击job信息页中的&quot;counter&quot;链接就能看到。<br />
<span id="more-14101"></span><br />
<img decoding="async" alt="hadoop job info page" src="https://www.codelast.com/wp-content/uploads/2024/04/hadoop_job_info_page.png" style="width: 339px; height: 361px;" /></p>
<p>本来嘛，点进这个页面，会看到正常的counter数据，但是，出问题的情况下，点进去看到的是这种情况：<br />
<img decoding="async" alt="hadoop counter info error" src="https://www.codelast.com/wp-content/uploads/2024/04/hadoop_counter_error.png" style="width: 561px; height: 144px;" /><br />
同时，在shell命令行你也会发现，该job没有任何counter信息输出。<br />
从错误信息页上，你得不到关于错误的任何有效信息，那个&quot;Error Details&quot;里也没有。<br />
虽然counter无法显示，但M-R job是可以正常跑完、正常输出数据的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
经过测试，我这个case的的问题是：在程序中添加了数量比较多的Hadoop counter造成的。<br />
什么算多？我不知道。我的程序里有240多个counter就出问题了，当我把counter缩减了一半，最终只有120多个counter的时候，counter信息统计就正常了。<br />
如果你遇到了类似问题，可以首先检查一下job中的counter数量是否太多。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：<br />
<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e7%9a%84counter%e9%a1%b5%e9%9d%a2%e6%97%a0%e6%b3%95%e6%98%be%e7%a4%ba%e7%9a%84%e9%97%ae%e9%a2%98error-500/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 解决IntelliJ idea启动崩溃：error occurred during error reporting (), id 0x6, SIGABRT (0x6) at pc=...</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3intellij-idea%e5%90%af%e5%8a%a8%e5%b4%a9%e6%ba%83%ef%bc%9aerror-occurred-during-error-reporting-id-0x6-sigabrt-0x6-at-pc/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3intellij-idea%e5%90%af%e5%8a%a8%e5%b4%a9%e6%ba%83%ef%bc%9aerror-occurred-during-error-reporting-id-0x6-sigabrt-0x6-at-pc/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Fri, 15 Mar 2024 09:48:13 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[crash]]></category>
		<category><![CDATA[IntelliJ IDEA]]></category>
		<category><![CDATA[SIGABRT]]></category>
		<category><![CDATA[启动]]></category>
		<category><![CDATA[崩溃]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14081</guid>

					<description><![CDATA[<div style="text-align: center;">
	<img decoding="async" alt="" src="https://www.codelast.com/wp-content/uploads/2024/03/intellij_idea_logo.jpeg" style="width: 225px; height: 225px;" /></div>
<p>有时候，一个用了好久、一直好用的方法突然失灵，并且还折腾了几天，真的会逼疯人。<br />
前几天我就遇到了这种破事：在Ubuntu开发机上自己升级IntelliJ idea到最新版之后，就无法再启动它。<br />
启动时永远会崩溃，无论是重启系统、删除IntelliJ idea的本地缓存，或者使用回旧版，都无法再启动它（仿佛什么文件被&#34;污染&#34;了，再也回不去了），十分烦人。经过几天各种方法的尝试，终于解决了问题，我的解决办法不具有普适性，但如果你遇到了此类问题，或许可以为你提供一些解决思路。<br />
<span id="more-14081"></span><br />
OS：<span style="color:#0000ff;">Ubuntu 20.04.6 LTS</span><br />
JDK：<span style="color:#0000ff;">1.8.0_382</span><br />
原来安装的IntelliJ idea版本：<span style="color:#b22222;">idea-IC-232.8660.185</span><br />
从JetBrains官网上下载的新版IntelliJ idea版本：<span style="color:#b22222;">idea-IC-233.14808.21</span><br />
我当时不是利用IDE里的升级功能来升级的，而是自己下载了新版的压缩包，解压出来一个&#160;idea-IC-233.14808.21 目录，直接进入 bin 目录下执行 idea.sh 来跑的新版。众所周知，这样跑起来之后，新版会自动把旧版里的配置引入进来，只要没有问题，是可以无缝切换到新版不需要重新配置的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
然而，启动新版的时候挂了，最后看到命令行报错：</p>
<blockquote>
<div>
		[error occurred during error reporting (), id 0x6, SIGABRT (0x6) at pc=0x00007fed3c5cf00b]</div>
<div>
		Aborted (core dumped)</div>
</blockquote>
<div>
	进不了IDE主界面。同时在/home目录下生成了一个内容超长的错误报告文件 java_error_in_idea_xxx.log</div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3intellij-idea%e5%90%af%e5%8a%a8%e5%b4%a9%e6%ba%83%ef%bc%9aerror-occurred-during-error-reporting-id-0x6-sigabrt-0x6-at-pc/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;">
	<img decoding="async" alt="" src="https://www.codelast.com/wp-content/uploads/2024/03/intellij_idea_logo.jpeg" style="width: 225px; height: 225px;" /></div>
<p>有时候，一个用了好久、一直好用的方法突然失灵，并且还折腾了几天，真的会逼疯人。<br />
前几天我就遇到了这种破事：在Ubuntu开发机上自己升级IntelliJ idea到最新版之后，就无法再启动它。<br />
启动时永远会崩溃，无论是重启系统、删除IntelliJ idea的本地缓存，或者使用回旧版，都无法再启动它（仿佛什么文件被&quot;污染&quot;了，再也回不去了），十分烦人。经过几天各种方法的尝试，终于解决了问题，我的解决办法不具有普适性，但如果你遇到了此类问题，或许可以为你提供一些解决思路。<br />
<span id="more-14081"></span><br />
OS：<span style="color:#0000ff;">Ubuntu 20.04.6 LTS</span><br />
JDK：<span style="color:#0000ff;">1.8.0_382</span><br />
原来安装的IntelliJ idea版本：<span style="color:#b22222;">idea-IC-232.8660.185</span><br />
从JetBrains官网上下载的新版IntelliJ idea版本：<span style="color:#b22222;">idea-IC-233.14808.21</span><br />
我当时不是利用IDE里的升级功能来升级的，而是自己下载了新版的压缩包，解压出来一个&nbsp;idea-IC-233.14808.21 目录，直接进入 bin 目录下执行 idea.sh 来跑的新版。众所周知，这样跑起来之后，新版会自动把旧版里的配置引入进来，只要没有问题，是可以无缝切换到新版不需要重新配置的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
然而，启动新版的时候挂了，最后看到命令行报错：</p>
<blockquote>
<div>
		[error occurred during error reporting (), id 0x6, SIGABRT (0x6) at pc=0x00007fed3c5cf00b]</div>
<div>
		Aborted (core dumped)</div>
</blockquote>
<div>
	进不了IDE主界面。同时在/home目录下生成了一个内容超长的错误报告文件 java_error_in_idea_xxx.log<br />
	我一开始并没有看这个log文件，而是按网上搜到的方法，分别尝试了：<br />
	1、重启系统<br />
	2、删除IntelliJ idea的缓存<br />
	3、使用回旧版IntelliJ idea<br />
	4、仿照<a href="https://youtrack.jetbrains.com/issue/IDEA-315192/IntelliJ-would-not-open-after-being-closed-once-on-Ubuntu-22.04-LTS.-The-only-solution-is-rebooting." rel="noopener" target="_blank">这个</a>类似的问题，卸载了snap又重新安装<br />
	以上方法都没用。<br />
	实在没辙了，只能硬着头皮看崩溃产生的日志文件&nbsp;java_error_in_idea_xxx.log，没想到一看就发现了端倪。<br />
	开头有一段内容是：</p>
<div>
<blockquote>
<div>
				# Problematic frame:</div>
<div>
				# C&nbsp; [x86_64-linux-gnu-tree-sitter-cpp.so+0x38ec09]&nbsp; tree_sitter_cpp_external_scanner_deserialize+0x179</div>
</blockquote>
<div>
<div>
				虽然我不知道它是什么确切的意思，但是这里写的是&quot;问题帧&quot;，说明崩溃和它有关。<br />
				<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
				再往下看日志，会看到：</p>
<blockquote>
<div>
						---------------&nbsp; T H R E A D&nbsp; ---------------</div>
<div>
						&nbsp;</div>
<div>
						Current thread (0x00007fec7c02b370):&nbsp; JavaThread &quot;AWT-EventQueue-0&quot; [_thread_in_native, id=352672, stack(0x00007feb95ae5000,0x00007feb95be6000)]</div>
<div>
						&nbsp;</div>
<div>
						Stack: [0x00007feb95ae5000,0x00007feb95be6000],&nbsp; sp=0x00007feb95be0310,&nbsp; free space=1004k</div>
<div>
						Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)</div>
<div>
						C&nbsp; [x86_64-linux-gnu-tree-sitter-cpp.so+0x38ec09]&nbsp; tree_sitter_cpp_external_scanner_deserialize+0x179</div>
<div>
						C&nbsp; [x86_64-linux-gnu-tree-sitter.so+0x30b3e]&nbsp; ts_parser_reset+0x30e</div>
<div>
						C&nbsp; [x86_64-linux-gnu-tree-sitter.so+0x2e329]&nbsp; ts_parser_set_language+0x399</div>
<div>
						C&nbsp; [x86_64-linux-gnu-tree-sitter.so+0xb4875]&nbsp; Java_org_treesitter_TSParser_ts_1parser_1set_1language+0x25</div>
<div>
						j&nbsp; org.treesitter.TSParser.ts_parser_set_language(JJ)Z+0</div>
<div>
						j&nbsp; org.treesitter.TSParser.setLanguage(Lorg/treesitter/TSLanguage;)Z+10</div>
<div>
						j&nbsp; ai.codegeex.plugin.lang.agent.d.a()V+64</div>
<div>
						j&nbsp; ai.codegeex.plugin.lang.agent.d.&lt;init&gt;()V+365</div>
<div>
						j&nbsp; ai.codegeex.plugin.lang.agent.d.a()Lai/codegeex/plugin/lang/agent/d;+10</div>
<div>
						j&nbsp; ai.codegeex.plugin.lang.agent.CodegeexAgentCompletionService.e()V+0</div>
<div>
						j&nbsp; ai.codegeex.plugin.lang.agent.CodegeexAgentCompletionService.&lt;init&gt;()V+266</div>
</blockquote>
<div>
<div>
						可见，和出问题的&quot;x86_64-linux-gnu-tree-sitter-cpp.so+0x38ec09&quot;有关系的插件，第一个出现的就是&quot;ai.codegeex.plugin&quot;，这个对应的就是我安装的CodeGeeX插件。</div>
<div>
						所以我怀疑，删除这个插件可以解决IntelliJ idea启动崩溃的问题。</div>
<div>
						在Ubuntu系统上，插件安装在这个目录下：<span style="color:#0000ff;">~/.local/share/JetBrains/IdeaIC2023.3</span></div>
<div>
						其中，IdeaIC2023.3是IntelliJ idea的版本号，每升级一个版本，~/.local/share/JetBrains 目录下都会生成一个新的目录。</div>
<div>
						在这个目录下，会看到有一个名为&quot;CodeGeeX&quot;的目录，这个目录就是CodeGeeX插件的安装目录，删除它即可。</div>
<div>
						然后再次尝试启动IntelliJ idea，发现已经可以正常启动了。<br />
						虽然我现在还不知道为什么CodeGeeX插件会引起这个问题，但是如果你像我一样，实在找不到IDE崩溃的原因时，删除可能有问题的插件或许是解决问题的一个办法。<br />
						<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
						<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
						转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
						感谢关注我的微信公众号（微信扫一扫）：<br />
						<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
						以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
							<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</p></div>
</p></div>
</p></div>
</p></div>
</p></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3intellij-idea%e5%90%af%e5%8a%a8%e5%b4%a9%e6%ba%83%ef%bc%9aerror-occurred-during-error-reporting-id-0x6-sigabrt-0x6-at-pc/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 和付费使用一年多的GitHub Copilot说再见</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%92%8c%e4%bb%98%e8%b4%b9%e4%bd%bf%e7%94%a8%e4%b8%80%e5%b9%b4%e5%a4%9a%e7%9a%84-github-copilot-%e8%af%b4%e5%86%8d%e8%a7%81/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%92%8c%e4%bb%98%e8%b4%b9%e4%bd%bf%e7%94%a8%e4%b8%80%e5%b9%b4%e5%a4%9a%e7%9a%84-github-copilot-%e8%af%b4%e5%86%8d%e8%a7%81/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Fri, 01 Mar 2024 19:16:53 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[AI辅助编程]]></category>
		<category><![CDATA[CodeGeeX]]></category>
		<category><![CDATA[GitHub Copilot]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14064</guid>

					<description><![CDATA[<div style="text-align: center;">
	<img decoding="async" alt="GitHub CoPilot" src="https://www.codelast.com/wp-content/uploads/2024/03/github_copilot_1.png" style="width: 800px; height: 213px;" /></div>
<div>
	&#160;</div>
<div>
	昨天，我的GitHub Copilot订阅到期了。付费使用了一年多，现在也决定不再续费，颇有些感受。<br />
	&#160;</div>
<div>
	从付费之前的热切期盼，到使用过程中的逐渐习惯，再到付费结束时的&#34;从容分手&#34;，我终究还是向现实投降，选择了穷人的活法。<br />
	&#160;</div>
<div>
	毕竟一个月10美元的费用，说它值或不值都可以找出充分的理由，只不过于我而言，GitHub Copilot已经不再有$10/月的吸引力罢了。<br />
	<span id="more-14064"></span></div>
<div style="text-align: center;">
	<img decoding="async" alt="GitHub CoPilot" src="https://www.codelast.com/wp-content/uploads/2024/03/github_copilot_2.png" style="width: 800px; height: 309px;" /></div>
<div>
<!--more--></div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	GitHub Copilot作为世界上第一款效果一流的AI辅助编程工具，是在2022年9月份正式上线的。之前，我和很多同行一样，时不时困在&#34;写代码&#8594;某些片段忘了怎么写&#8594;搜Google&#8594;复制粘贴网上的代码测试&#8594;继续写代码&#34;的循环中。这种熟悉而又重复的感觉长时间下来会给人积累不少负能量。<br />
	&#160;</div>
<div>
	直到GitHub Copilot出现，在科技媒体的渲染、宣传下，以及民间艺人的自测报告加持下，它被赋予了一个响当当的名字：牛B！<br />
	&#160;</div>
<div>
	于是我心动了。在试用了一个月，又继续付费体验了一个月之后，GitHub Copilot给我的震动让我相信：它一定能在开发过程中为我节省海量时间。于是在2023年初，我下定决心要续一年的费。<br />
	&#160;</div>
<div>
	$10/月的费用，对很多开发者来说可能要下很大决心才能下手。当时我账户上有一个优惠，以90多美元的价格续了一年的费，也就是不到700人民币一年。<br />
	&#160;</div>
<div>
	GitHub Copilot代码补全的准确度令人印象深刻。我觉得最爽的一点就是：它补全中文注释的结果令我十分满意。无论是补全class头部的比较长的注释，还是在写代码的过程中，补全一行的那种注释，我都觉得它能&#34;想我所想，写我想写&#34;。<br />
	&#160;</div>
<div>
	当然也有最不爽的一点，就是它连接服务器时不时会卡顿&#8212;&#8212;服务器在国外，可以理解。<br />
	&#160;</div>
<div style="text-align: center;">
	<img decoding="async" alt="alternatives" src="https://www.codelast.com/wp-content/uploads/2024/03/alternative.jpg" style="width: 750px; height: 320px;" /></div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	在2023年初那时，如果你想找到一个GitHub Copilot的免费版&#34;平替&#34;，那么选择并不多。国内的aiXcoder、CodeGeeX算是比较知名的其二。</div>
<div style="text-align: center;">
	<img decoding="async" alt="aiXcoder" src="https://www.codelast.com/wp-content/uploads/2024/03/aixcoder.jpg" style="width: 360px; height: 147px;" /></div>
<div>
	aiXcoder的最初几个版本我一直觉得它的设计是真的&#34;有病&#34;&#8212;&#8212;需要在本地安装一个后端软件来做inference。由于和系统相关，这显然会导致在很多Linux发行版上会用不了。比如我曾经在Ubuntu 16.04上尝试过安装aiXcoder的本地推理软件，无奈由于依赖库的问题装不上，到官方QQ群里反馈问题，官方的开发也只是确认了问题，却不给任何解决方案。想必这种没有任何KPI又赚不了一毛钱的事情，鬼才会给你开发！<br />
	&#160;</div>
<div>
	所以我毫不犹豫地抛弃了aiXcoder。</div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	GitHub Copilot那种&#34;一个插件解决所有问题&#34;、&#34;推理在云端完成&#34;的机制，就基本避开了系统版本的差异，没有了依赖库的问题。<br />
	&#160;</div>
<div style="text-align: center;">
	<img decoding="async" alt="CodeGeeX" src="https://www.codelast.com/wp-content/uploads/2024/03/codegeex.png" style="width: 727px; height: 153px;" /></div>
<div>
	<br />
	在2023年初，国产的CodeGeeX算是辅助编程领域的另一个耀眼明星。它和GitHub Copilot一样，inference都在云端完成，安装一个插件搞定一切&#8212;&#8212;这才像是一个正常的辅助编程软件应有的样子。<br />
	&#160;</div>
<div>
	我当时在大概10个case上详细对比过GitHub Copilot和CodeGeeX的效果，结论当然不出意外：GitHub Copilot全面碾压CodeGeeX&#8212;&#8212;这里不是指在某些技术指标上进行对比(比如用于评估代码生成质量的测试集等)，而是纯粹从个人的直观感受上看二者的输出谁更好。<br />
	&#160;</div>
<div>
	所以，实话实说，在2023年初的时候，经过我个人的测试，我宁可选择花700块这么大一笔费用去买GitHub Copilot，也不愿每天频繁使用免费的CodeGeeX，因为它当时的代码补全效果确实不太行，而且对某些编程语言的支持也很菜（比如Apache Pig），会影响我的开发工作。</div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%92%8c%e4%bb%98%e8%b4%b9%e4%bd%bf%e7%94%a8%e4%b8%80%e5%b9%b4%e5%a4%9a%e7%9a%84-github-copilot-%e8%af%b4%e5%86%8d%e8%a7%81/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;">
	<img decoding="async" alt="GitHub CoPilot" src="https://www.codelast.com/wp-content/uploads/2024/03/github_copilot_1.png" style="width: 800px; height: 213px;" /></div>
<div>
	&nbsp;</div>
<div>
	昨天，我的GitHub Copilot订阅到期了。付费使用了一年多，现在也决定不再续费，颇有些感受。<br />
	&nbsp;</div>
<div>
	从付费之前的热切期盼，到使用过程中的逐渐习惯，再到付费结束时的&quot;从容分手&quot;，我终究还是向现实投降，选择了穷人的活法。<br />
	&nbsp;</div>
<div>
	毕竟一个月10美元的费用，说它值或不值都可以找出充分的理由，只不过于我而言，GitHub Copilot已经不再有$10/月的吸引力罢了。<br />
	<span id="more-14064"></span></div>
<div style="text-align: center;">
	<img decoding="async" alt="GitHub CoPilot" src="https://www.codelast.com/wp-content/uploads/2024/03/github_copilot_2.png" style="width: 800px; height: 309px;" /></div>
<div>
<!--more--></div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	GitHub Copilot作为世界上第一款效果一流的AI辅助编程工具，是在2022年9月份正式上线的。之前，我和很多同行一样，时不时困在&quot;写代码&rarr;某些片段忘了怎么写&rarr;搜Google&rarr;复制粘贴网上的代码测试&rarr;继续写代码&quot;的循环中。这种熟悉而又重复的感觉长时间下来会给人积累不少负能量。<br />
	&nbsp;</div>
<div>
	直到GitHub Copilot出现，在科技媒体的渲染、宣传下，以及民间艺人的自测报告加持下，它被赋予了一个响当当的名字：牛B！<br />
	&nbsp;</div>
<div>
	于是我心动了。在试用了一个月，又继续付费体验了一个月之后，GitHub Copilot给我的震动让我相信：它一定能在开发过程中为我节省海量时间。于是在2023年初，我下定决心要续一年的费。<br />
	&nbsp;</div>
<div>
	$10/月的费用，对很多开发者来说可能要下很大决心才能下手。当时我账户上有一个优惠，以90多美元的价格续了一年的费，也就是不到700人民币一年。<br />
	&nbsp;</div>
<div>
	GitHub Copilot代码补全的准确度令人印象深刻。我觉得最爽的一点就是：它补全中文注释的结果令我十分满意。无论是补全class头部的比较长的注释，还是在写代码的过程中，补全一行的那种注释，我都觉得它能&quot;想我所想，写我想写&quot;。<br />
	&nbsp;</div>
<div>
	当然也有最不爽的一点，就是它连接服务器时不时会卡顿&mdash;&mdash;服务器在国外，可以理解。<br />
	&nbsp;</div>
<div style="text-align: center;">
	<img decoding="async" alt="alternatives" src="https://www.codelast.com/wp-content/uploads/2024/03/alternative.jpg" style="width: 750px; height: 320px;" /></div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	在2023年初那时，如果你想找到一个GitHub Copilot的免费版&quot;平替&quot;，那么选择并不多。国内的aiXcoder、CodeGeeX算是比较知名的其二。</div>
<div style="text-align: center;">
	<img decoding="async" alt="aiXcoder" src="https://www.codelast.com/wp-content/uploads/2024/03/aixcoder.jpg" style="width: 360px; height: 147px;" /></div>
<div>
	aiXcoder的最初几个版本我一直觉得它的设计是真的&quot;有病&quot;&mdash;&mdash;需要在本地安装一个后端软件来做inference。由于和系统相关，这显然会导致在很多Linux发行版上会用不了。比如我曾经在Ubuntu 16.04上尝试过安装aiXcoder的本地推理软件，无奈由于依赖库的问题装不上，到官方QQ群里反馈问题，官方的开发也只是确认了问题，却不给任何解决方案。想必这种没有任何KPI又赚不了一毛钱的事情，鬼才会给你开发！<br />
	&nbsp;</div>
<div>
	所以我毫不犹豫地抛弃了aiXcoder。</div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	GitHub Copilot那种&quot;一个插件解决所有问题&quot;、&quot;推理在云端完成&quot;的机制，就基本避开了系统版本的差异，没有了依赖库的问题。<br />
	&nbsp;</div>
<div style="text-align: center;">
	<img decoding="async" alt="CodeGeeX" src="https://www.codelast.com/wp-content/uploads/2024/03/codegeex.png" style="width: 727px; height: 153px;" /></div>
<div>
	<br />
	在2023年初，国产的CodeGeeX算是辅助编程领域的另一个耀眼明星。它和GitHub Copilot一样，inference都在云端完成，安装一个插件搞定一切&mdash;&mdash;这才像是一个正常的辅助编程软件应有的样子。<br />
	&nbsp;</div>
<div>
	我当时在大概10个case上详细对比过GitHub Copilot和CodeGeeX的效果，结论当然不出意外：GitHub Copilot全面碾压CodeGeeX&mdash;&mdash;这里不是指在某些技术指标上进行对比(比如用于评估代码生成质量的测试集等)，而是纯粹从个人的直观感受上看二者的输出谁更好。<br />
	&nbsp;</div>
<div>
	所以，实话实说，在2023年初的时候，经过我个人的测试，我宁可选择花700块这么大一笔费用去买GitHub Copilot，也不愿每天频繁使用免费的CodeGeeX，因为它当时的代码补全效果确实不太行，而且对某些编程语言的支持也很菜（比如Apache Pig），会影响我的开发工作。</div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></div>
<div>
	然而，在2023年一整年，CodeGeeX做了令人印象深刻的重大改进，不仅代码补全的质量提高很多，而且还增加了大量新功能，三言两语无法说完。因此，在2024年的今天，当我的GitHub Copilot需要再次付费的时候，除非它降价到原来的10%（我当然知道这不可能），否则我是不会再续费了，我会选择用免费的国产平替：CodeGeeX。<br />
	&nbsp;</div>
<div>
	2023年至今，除了CodeGeeX的巨大进步之外，市场上还出现了大量免费竞品，包括Codeium（国外），Fitten Code（国产）等等，它们虽然可能比GitHub Copilot还有差距，但是你要相信：只要你不是特别挑剔，日常使用绝对够了。</div>
<div>
	&nbsp;</div>
<div>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%92%8c%e4%bb%98%e8%b4%b9%e4%bd%bf%e7%94%a8%e4%b8%80%e5%b9%b4%e5%a4%9a%e7%9a%84-github-copilot-%e8%af%b4%e5%86%8d%e8%a7%81/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 在Apache Pig中把数据按指定字段分组，每组取时间最新的一条记录</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%95%b0%e6%8d%ae%e6%8c%89%e6%8c%87%e5%ae%9a%e5%ad%97%e6%ae%b5%e5%88%86%e7%bb%84%ef%bc%8c%e6%af%8f%e7%bb%84%e5%8f%96%e6%97%b6%e9%97%b4/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%95%b0%e6%8d%ae%e6%8c%89%e6%8c%87%e5%ae%9a%e5%ad%97%e6%ae%b5%e5%88%86%e7%bb%84%ef%bc%8c%e6%af%8f%e7%bb%84%e5%8f%96%e6%97%b6%e9%97%b4/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 15 Nov 2023 08:15:25 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[apache pig]]></category>
		<category><![CDATA[GROUP]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=13967</guid>

					<description><![CDATA[<p>查看更多Apache Pig的教程请点击<a href="https://www.codelast.com/?p=4550" rel="noopener" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>用Apache Pig处理大数据时，经常会有这种需求：把输入数据按指定的字段group，并且每个group内只输出时间最新的一条记录。<br />
<span id="more-13967"></span><br />
举个例子。有数据文件 input.txt ：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">10&#160;&#160;&#160;&#160;&#160;&#160;a&#160;&#160;&#160;&#160;&#160;&#160;&#160;1,2,3
9&#160;&#160;&#160;&#160;&#160;&#160;&#160;b&#160;&#160;&#160;&#160;&#160;&#160;&#160;1,2
8&#160;&#160;&#160;&#160;&#160;&#160;&#160;a&#160;&#160;&#160;&#160;&#160;&#160;&#160;2,3,4
13&#160;&#160;&#160;&#160;&#160;&#160;a&#160;&#160;&#160;&#160;&#160;&#160;&#160;1,2,3,4
6&#160;&#160;&#160;&#160;&#160;&#160;&#160;b&#160;&#160;&#160;&#160;&#160;&#160;&#160;1
</code></pre>
</section>
<p>该数据的三个字段分别代表：<span style="background-color: rgb(255, 255, 255); color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre;">time（时间戳），userId（用户id），userInterest（用户兴趣id）<br />
现在，要找出每个用户时间最新的</span><span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest，</span><span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">应该怎么做？</span><br />
<span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">即：对用户 a，最新的时间戳是13，</span><span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest是1,2,3,4；对用户 b，最新的时间戳是9，</span><span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest是1,2。</span><br />
<span style="color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">直接上代码：</span></p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">A&#160;=&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">LOAD</span>&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#39;input.txt&#39;</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">AS</span>&#160;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">time</span>:&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">long</span>,&#160;userId:&#160;chararray,&#160;userInterest:&#160;chararray);
A&#160;=&#160;FOREACH&#160;A&#160;GENERATE&#160;time,&#160;userId,&#160;userInterest;
B&#160;=&#160;GROUP&#160;A&#160;BY&#160;userId;
<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">--&#160;每个userId取时间最新的一条记录</span>
C&#160;=&#160;FOREACH&#160;B&#160;{
&#160;&#160;&#160;&#160;SORTED&#160;=&#160;ORDER&#160;A&#160;BY&#160;time&#160;DESC;
&#160;&#160;&#160;&#160;ONE_RECORD&#160;=&#160;LIMIT&#160;SORTED&#160;1;
&#160;&#160;&#160;&#160;GENERATE&#160;FLATTEN(ONE_RECORD);
};
DUMP&#160;C;
</code></pre>
</section>
<p>
在嵌套的FOREACH语句中，首先用ORDER BY对同一个group内的数据进行了降序排序，再用LIMIT取一条记录，由于是按time降序排序，因此LIMIT 1取到的就是时间戳最大的那条记录，即时间最新的记录。<br />
<span style="font-size: 16px; color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; white-space: pre; background-color: rgb(255, 255, 255);">输出：</span></p>
<blockquote>
<div>
		(13,a,1,2,3,4)</div>
<div>
		(9,b,1,2)</div>
</blockquote>
<p><span style="font-size: 16px; color: rgb(59, 59, 59); font-family: &#34;Droid Sans Mono&#34;, &#34;monospace&#34;, monospace; white-space: pre; background-color: rgb(255, 255, 255);">可见这个结果和我们前面人工判断出来的正确结果一致。</span></p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%95%b0%e6%8d%ae%e6%8c%89%e6%8c%87%e5%ae%9a%e5%ad%97%e6%ae%b5%e5%88%86%e7%bb%84%ef%bc%8c%e6%af%8f%e7%bb%84%e5%8f%96%e6%97%b6%e9%97%b4/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>查看更多Apache Pig的教程请点击<a href="https://www.codelast.com/?p=4550" rel="noopener" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>用Apache Pig处理大数据时，经常会有这种需求：把输入数据按指定的字段group，并且每个group内只输出时间最新的一条记录。<br />
<span id="more-13967"></span><br />
举个例子。有数据文件 input.txt ：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1,2,3
9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1,2
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2,3,4
13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1,2,3,4
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1
</code></pre>
</section>
<p>该数据的三个字段分别代表：<span style="background-color: rgb(255, 255, 255); color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre;">time（时间戳），userId（用户id），userInterest（用户兴趣id）<br />
现在，要找出每个用户时间最新的</span><span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest，</span><span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">应该怎么做？</span><br />
<span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">即：对用户 a，最新的时间戳是13，</span><span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest是1,2,3,4；对用户 b，最新的时间戳是9，</span><span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">userInterest是1,2。</span><br />
<span style="color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; font-size: 16px; white-space: pre; background-color: rgb(255, 255, 255);">直接上代码：</span></p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">A&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">LOAD</span>&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#39;input.txt&#39;</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">AS</span>&nbsp;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">time</span>:&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">long</span>,&nbsp;userId:&nbsp;chararray,&nbsp;userInterest:&nbsp;chararray);
A&nbsp;=&nbsp;FOREACH&nbsp;A&nbsp;GENERATE&nbsp;time,&nbsp;userId,&nbsp;userInterest;
B&nbsp;=&nbsp;GROUP&nbsp;A&nbsp;BY&nbsp;userId;
<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">--&nbsp;每个userId取时间最新的一条记录</span>
C&nbsp;=&nbsp;FOREACH&nbsp;B&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;SORTED&nbsp;=&nbsp;ORDER&nbsp;A&nbsp;BY&nbsp;time&nbsp;DESC;
&nbsp;&nbsp;&nbsp;&nbsp;ONE_RECORD&nbsp;=&nbsp;LIMIT&nbsp;SORTED&nbsp;1;
&nbsp;&nbsp;&nbsp;&nbsp;GENERATE&nbsp;FLATTEN(ONE_RECORD);
};
DUMP&nbsp;C;
</code></pre>
</section>
<p>
在嵌套的FOREACH语句中，首先用ORDER BY对同一个group内的数据进行了降序排序，再用LIMIT取一条记录，由于是按time降序排序，因此LIMIT 1取到的就是时间戳最大的那条记录，即时间最新的记录。<br />
<span style="font-size: 16px; color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; white-space: pre; background-color: rgb(255, 255, 255);">输出：</span></p>
<blockquote>
<div>
		(13,a,1,2,3,4)</div>
<div>
		(9,b,1,2)</div>
</blockquote>
<p><span style="font-size: 16px; color: rgb(59, 59, 59); font-family: &quot;Droid Sans Mono&quot;, &quot;monospace&quot;, monospace; white-space: pre; background-color: rgb(255, 255, 255);">可见这个结果和我们前面人工判断出来的正确结果一致。</span></p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：<br />
<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%95%b0%e6%8d%ae%e6%8c%89%e6%8c%87%e5%ae%9a%e5%ad%97%e6%ae%b5%e5%88%86%e7%bb%84%ef%bc%8c%e6%af%8f%e7%bb%84%e5%8f%96%e6%97%b6%e9%97%b4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 在Apache Pig中把时间字符串转换成时间戳</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%97%b6%e9%97%b4%e5%ad%97%e7%ac%a6%e4%b8%b2%e8%bd%ac%e6%8d%a2%e6%88%90%e6%97%b6%e9%97%b4%e6%88%b3/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%97%b6%e9%97%b4%e5%ad%97%e7%ac%a6%e4%b8%b2%e8%bd%ac%e6%8d%a2%e6%88%90%e6%97%b6%e9%97%b4%e6%88%b3/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Thu, 12 Oct 2023 09:37:25 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[apache pig]]></category>
		<category><![CDATA[时间字符串]]></category>
		<category><![CDATA[时间戳]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=13959</guid>

					<description><![CDATA[<p>查看更多Apache Pig的教程请点击<a href="https://www.codelast.com/?p=4550" target="_blank" rel="noopener"><span style="background-color:#ffa07a;">这里</span></a>。</p>
<p>在Apache Pig中，怎样把 <span style="color:#ff0000;">2023-10-11_10:57:56</span> 这种格式的时间字符串，转成整型的时间戳？<br />
话不多说，直接上代码。<br />
假设输入数据文件 1.txt，其格式是一行一个时间字符串。<br />
<span id="more-13959"></span></p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">A&#160;=&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">LOAD</span>&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#39;1.txt&#39;</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">AS</span>&#160;(dt:&#160;chararray);
A&#160;=&#160;FOREACH&#160;A&#160;GENERATE&#160;ToDate(dt,&#160;&#39;yyyy-MM-dd_HH:mm:ss&#39;)&#160;AS&#160;date;
B&#160;=&#160;FOREACH&#160;A&#160;GENERATE&#160;ToUnixTime(date)&#160;AS&#160;ts;
DUMP&#160;B;
</code></pre>
</section>
<p>
输出结果形如：</p>
<blockquote>
<p>
		1696993076</p>
</blockquote>
<p>
可见，这样得到的时间戳单位是&#8220;秒&#8221;。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&#160;版权声明&#160;<span style="color: rgb(255, 0, 0);">➤➤</span>&#160;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&#160;<br />
感谢关注我的微信公众号（微信扫一扫）：<br />
<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" />&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%97%b6%e9%97%b4%e5%ad%97%e7%ac%a6%e4%b8%b2%e8%bd%ac%e6%8d%a2%e6%88%90%e6%97%b6%e9%97%b4%e6%88%b3/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>查看更多Apache Pig的教程请点击<a href="https://www.codelast.com/?p=4550" target="_blank" rel="noopener"><span style="background-color:#ffa07a;">这里</span></a>。</p>
<p>在Apache Pig中，怎样把 <span style="color:#ff0000;">2023-10-11_10:57:56</span> 这种格式的时间字符串，转成整型的时间戳？<br />
话不多说，直接上代码。<br />
假设输入数据文件 1.txt，其格式是一行一个时间字符串。<br />
<span id="more-13959"></span></p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">A&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">LOAD</span>&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#39;1.txt&#39;</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">AS</span>&nbsp;(dt:&nbsp;chararray);
A&nbsp;=&nbsp;FOREACH&nbsp;A&nbsp;GENERATE&nbsp;ToDate(dt,&nbsp;&#39;yyyy-MM-dd_HH:mm:ss&#39;)&nbsp;AS&nbsp;date;
B&nbsp;=&nbsp;FOREACH&nbsp;A&nbsp;GENERATE&nbsp;ToUnixTime(date)&nbsp;AS&nbsp;ts;
DUMP&nbsp;B;
</code></pre>
</section>
<p>
输出结果形如：</p>
<blockquote>
<p>
		1696993076</p>
</blockquote>
<p>
可见，这样得到的时间戳单位是&ldquo;秒&rdquo;。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：<br />
<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%9c%a8apache-pig%e4%b8%ad%e6%8a%8a%e6%97%b6%e9%97%b4%e5%ad%97%e7%ac%a6%e4%b8%b2%e8%bd%ac%e6%8d%a2%e6%88%90%e6%97%b6%e9%97%b4%e6%88%b3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] JAVA map-reduce job中，reduce()方法漏写 @Override 注解引起的问题</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e4%b8%ad%ef%bc%8creduce%e6%96%b9%e6%b3%95%e6%bc%8f%e5%86%99-override-%e6%b3%a8%e8%a7%a3%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e4%b8%ad%ef%bc%8creduce%e6%96%b9%e6%b3%95%e6%bc%8f%e5%86%99-override-%e6%b3%a8%e8%a7%a3%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sun, 06 Aug 2023 12:12:10 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[map-reduce job]]></category>
		<category><![CDATA[类型错误]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=13934</guid>

					<description><![CDATA[<p>有一个JAVA写的map-reduce&#160;job，mapper输出的key、value类型分别为Text、NullWritable，所以reducer应该像下面这样写：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="java language-java hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">static</span>&#160;<span class="hljs-class" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">class</span>&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">QuerySegmentResultFromKVReducer</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">extends</span>&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">Reducer</span>&#60;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">Text</span>,&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>,&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>,&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>&#62;&#160;</span>{

&#160;&#160;<span class="hljs-meta" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(91, 218, 237); word-wrap: inherit !important; word-break: inherit !important;">@Override</span>
&#160;&#160;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">protected</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">void</span>&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">setup</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(Reducer.Context&#160;context)</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">throws</span>&#160;IOException,&#160;InterruptedException&#160;</span>{
&#160;&#160;}

&#160;&#160;<span class="hljs-meta" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(91, 218, 237); word-wrap: inherit !important; word-break: inherit !important;">@Override</span>
&#160;&#160;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">protected</span>&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">void</span>&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">cleanup</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(Reducer.Context&#160;context)</span></span></code></pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e4%b8%ad%ef%bc%8creduce%e6%96%b9%e6%b3%95%e6%bc%8f%e5%86%99-override-%e6%b3%a8%e8%a7%a3%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<p>有一个JAVA写的map-reduce&nbsp;job，mapper输出的key、value类型分别为Text、NullWritable，所以reducer应该像下面这样写：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="java language-java hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">static</span>&nbsp;<span class="hljs-class" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">class</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">QuerySegmentResultFromKVReducer</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">extends</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">Reducer</span>&lt;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">Text</span>,&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>,&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>,&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">NullWritable</span>&gt;&nbsp;</span>{

&nbsp;&nbsp;<span class="hljs-meta" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(91, 218, 237); word-wrap: inherit !important; word-break: inherit !important;">@Override</span>
&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">protected</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">setup</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(Reducer.Context&nbsp;context)</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">throws</span>&nbsp;IOException,&nbsp;InterruptedException&nbsp;</span>{
&nbsp;&nbsp;}

&nbsp;&nbsp;<span class="hljs-meta" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(91, 218, 237); word-wrap: inherit !important; word-break: inherit !important;">@Override</span>
&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">protected</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">cleanup</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(Reducer.Context&nbsp;context)</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">throws</span>&nbsp;IOException,&nbsp;InterruptedException&nbsp;</span>{
&nbsp;&nbsp;}

&nbsp;&nbsp;<span class="hljs-meta" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(91, 218, 237); overflow-wrap: inherit !important; word-break: inherit !important;">@Override</span>
&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">protected</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">reduce</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(Text&nbsp;key,&nbsp;Iterable&lt;NullWritable&gt;&nbsp;values,&nbsp;Context&nbsp;context)</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">throws</span>&nbsp;IOException,&nbsp;InterruptedException&nbsp;</span>{
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">//<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">TODO:</span></span>
&nbsp;&nbsp;}
}
</code></pre>
</section>
<p>在这里，reducer输出的key、value类型都是NullWritable，我们不用关心，这不是本文的关注点。<br />
<span id="more-13934"></span><br />
如果reduce()方法漏掉了&nbsp;<span style="color:#ff0000;">@Override</span>&nbsp;注解，并且把&nbsp; Reducer&lt;Text, NullWritable, NullWritable, NullWritable&gt;&nbsp;错误地写成了&nbsp;Reducer&lt;Text, Text, NullWritable, NullWritable&gt;，会发现编译并不报错。<br />
但是，当你跑这个job的时候，诡异的事情就来了。你会发现，你在&ldquo;TODO:&rdquo;那里写的reduce逻辑并没有执行，即使没有用 context.write()&nbsp;方法把任何数据输出到HDFS上，Hadoop counter仍然显示该job输出了和reducer输入一样多的数据。<br />
从现象上看，就像是执行了一个默认的Reducer，把reducer的输入数据原样输出。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
所以这里不得不强调，一定不要漏写&nbsp;<span style="color: rgb(255, 0, 0);">@Override</span>&nbsp;注解！有这个注解的时候，IDE就会提示错误，编译就会失败！</p>
<div>
	@Override 注解是可选的，如果删除了它，编译器不会报错，因为在 JAVA 中，重写一个方法时不使用 @Override 注解也是允许的。</div>
<div>
	&nbsp;</div>
<div>
	但是，建议在重写父类或接口中的方法时使用 @Override 注解。这样做有以下几个好处：</div>
<div>
	➤ 增加代码可读性：通过使用 @Override 注解，其他开发人员可以清楚地知道该方法是对父类或接口中的方法进行重写的，代码更易于理解。</div>
<div>
	➤ 防止错误：如果你错误地拼写了要重写的方法名，或者方法签名不正确，编译器会给出错误提示，帮助你发现潜在的问题。</div>
<div>
	➤ 保证代码的健壮性：如果父类或接口中的方法发生了变化，使用 @Override 注解的方法会在编译时产生错误，提醒你需要更新重写的方法。</div>
<p>
	在本文的例子中，如果reduce()方法没有写 @Override 注解，那么当reducer类错误地定义成了extends Reducer&lt;Text, Text, NullWritable, NullWritable&gt;的时候，IDE并不会发现reduce()方法有错，从而让你误以为一切正常。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-java-map-reduce-job%e4%b8%ad%ef%bc%8creduce%e6%96%b9%e6%b3%95%e6%bc%8f%e5%86%99-override-%e6%b3%a8%e8%a7%a3%e5%bc%95%e8%b5%b7%e7%9a%84%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 解决Map-Reduce job OOM(Java Heap Space)错误的一个方法：调整内存参数</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3map-reduce-job-oomjava-heap-space%e9%94%99%e8%af%af%e7%9a%84%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%ef%bc%9a%e8%b0%83%e6%95%b4%e5%86%85%e5%ad%98%e5%8f%82%e6%95%b0/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3map-reduce-job-oomjava-heap-space%e9%94%99%e8%af%af%e7%9a%84%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%ef%bc%9a%e8%b0%83%e6%95%b4%e5%86%85%e5%ad%98%e5%8f%82%e6%95%b0/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 19 Jun 2023 05:21:18 +0000</pubDate>
				<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[Java Heap Space]]></category>
		<category><![CDATA[M-R job]]></category>
		<category><![CDATA[pig]]></category>
		<category><![CDATA[调大内存]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=13923</guid>

					<description><![CDATA[<p>无论是JAVA M-R job还是Pig M-R job发生Java Heap Space错误，一般情况下，我们要通过定位输入数据里的异常情况再想办法解决，例如，你在程序中对某个key做了GROUP操作，但输入数据中可能该key有大量记录，这就有可能导致job OOM。<br />
这个问题取决于数据的具体情况，以及程序实现逻辑，所以这里就不提了。<br />
本文要说的是：有时候程序实现/输入数据的问题&#8220;不是特别严重&#8221;，我们可以通过调整M-R job的内存参数来解决。<br />
<span id="more-13923"></span><br />
对JAVA M-R job，通过 -D 设置如下参数：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="bash language-bash hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">&#160;&#160;-D&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#34;mapreduce.map.memory.mb=8192&#34;</span>&#160;\
&#160;&#160;-D&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#34;mapreduce.reduce.memory.mb=8192&#34;</span>&#160;\
&#160;&#160;-D&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#34;mapreduce.map.java.opts=-Xmx6144m&#34;</span>&#160;\
&#160;&#160;-D&#160;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#34;mapreduce.reduce.java.opts=-Xmx6144m&#34;</span>&#160;\
</code></pre>
</section>
<p>
对Apache Pig M-R job，在Pig代码中添加如下语句：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&#160;mapreduce.map.memory.mb&#160;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">8192</span>;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&#160;mapreduce.reduce.memory.mb&#160;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">8192</span>;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&#160;mapreduce.map.java.opts&#160;-Xmx6144m;</code></pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3map-reduce-job-oomjava-heap-space%e9%94%99%e8%af%af%e7%9a%84%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%ef%bc%9a%e8%b0%83%e6%95%b4%e5%86%85%e5%ad%98%e5%8f%82%e6%95%b0/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<p>无论是JAVA M-R job还是Pig M-R job发生Java Heap Space错误，一般情况下，我们要通过定位输入数据里的异常情况再想办法解决，例如，你在程序中对某个key做了GROUP操作，但输入数据中可能该key有大量记录，这就有可能导致job OOM。<br />
这个问题取决于数据的具体情况，以及程序实现逻辑，所以这里就不提了。<br />
本文要说的是：有时候程序实现/输入数据的问题&ldquo;不是特别严重&rdquo;，我们可以通过调整M-R job的内存参数来解决。<br />
<span id="more-13923"></span><br />
对JAVA M-R job，通过 -D 设置如下参数：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="bash language-bash hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">&nbsp;&nbsp;-D&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;mapreduce.map.memory.mb=8192&quot;</span>&nbsp;\
&nbsp;&nbsp;-D&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;mapreduce.reduce.memory.mb=8192&quot;</span>&nbsp;\
&nbsp;&nbsp;-D&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;mapreduce.map.java.opts=-Xmx6144m&quot;</span>&nbsp;\
&nbsp;&nbsp;-D&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;mapreduce.reduce.java.opts=-Xmx6144m&quot;</span>&nbsp;\
</code></pre>
</section>
<p>
对Apache Pig M-R job，在Pig代码中添加如下语句：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="sql language-sql hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&nbsp;mapreduce.map.memory.mb&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">8192</span>;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&nbsp;mapreduce.reduce.memory.mb&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">8192</span>;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&nbsp;mapreduce.map.java.opts&nbsp;-Xmx6144m;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">SET</span>&nbsp;mapreduce.reduce.java.opts&nbsp;-Xmx6144m;
</code></pre>
</section>
<p>
其中，第1、2个参数需要你根据Hadoop集群的情况自行调整，第3、4个参数设置成第1、2个参数的70%～80%</p>
<p>
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：<br />
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
	以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%a7%a3%e5%86%b3map-reduce-job-oomjava-heap-space%e9%94%99%e8%af%af%e7%9a%84%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95%ef%bc%9a%e8%b0%83%e6%95%b4%e5%86%85%e5%ad%98%e5%8f%82%e6%95%b0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
