WWW.YOUINFO.SITE
标签聚合 转换器

/tag/转换器

LinuxDo 最新话题 · 2026-05-26 13:42:49+08:00 · tech

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NAT64 转换器 - IPv4 到 IPv6</title> <style> :root { --bg: #f5f7fb; --card-bg: #ffffff; --text: #1e293b; --text-secondary: #475569; --border: #e2e8f0; --accent: #2563eb; --accent-hover: #1d4ed8; --success: #059669; --error: #dc2626; --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -2px rgba(0, 0, 0, 0.05); --radius: 12px; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; background: linear-gradient(135deg, #f0f4ff 0%, #e8edf5 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; color: var(--text); } .container { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow), 0 10px 25px -5px rgba(0, 0, 0, 0.08); width: 100%; max-width: 700px; padding: 2.5rem; border: 1px solid var(--border); transition: all 0.2s ease; } h1 { font-size: 1.8rem; font-weight: 700; margin-bottom: 0.5rem; letter-spacing: -0.5px; display: flex; align-items: center; gap: 0.5rem; } h1 span { background: var(--accent); color: white; font-size: 0.9rem; padding: 0.2rem 0.8rem; border-radius: 20px; font-weight: 500; letter-spacing: 0; } .subtitle { color: var(--text-secondary); margin-bottom: 2rem; font-size: 0.95rem; border-left: 3px solid var(--accent); padding-left: 0.8rem; } .form-group { margin-bottom: 1.5rem; } label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.4rem; color: var(--text); } .input-wrapper { display: flex; align-items: center; gap: 0.5rem; background: #f8fafc; border: 1px solid var(--border); border-radius: 8px; padding: 0.5rem 0.8rem; transition: border-color 0.2s, box-shadow 0.2s; } .input-wrapper:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); } .input-wrapper input { border: none; background: transparent; flex: 1; font-size: 1rem; padding: 0.5rem 0; outline: none; font-family: 'JetBrains Mono', 'Fira Code', monospace; color: var(--text); } .input-wrapper .icon { color: var(--text-secondary); font-size: 1.1rem; } select { width: 100%; padding: 0.75rem 0.8rem; border: 1px solid var(--border); border-radius: 8px; background: #f8fafc; font-size: 0.95rem; font-family: 'JetBrains Mono', 'Fira Code', monospace; color: var(--text); outline: none; cursor: pointer; transition: border-color 0.2s, box-shadow 0.2s; appearance: none; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="%23475569" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>'); background-repeat: no-repeat; background-position: right 0.8rem center; background-size: 1.2rem; } select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); } .custom-prefix { margin-top: 0.8rem; display: none; } .custom-prefix.show { display: block; } .result-box { background: #f1f5f9; border-radius: 8px; padding: 1.2rem; margin: 1.8rem 0 1rem; border: 1px solid var(--border); word-break: break-all; } .result-label { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-secondary); margin-bottom: 0.3rem; } .result-ipv6 { font-family: 'JetBrains Mono', 'Fira Code', monospace; font-size: 1.3rem; font-weight: 700; color: var(--accent); background: white; padding: 0.5rem 0.8rem; border-radius: 6px; display: inline-block; max-width: 100%; overflow-wrap: anywhere; border: 1px solid #cbd5e1; } .error-message { color: var(--error); font-size: 0.9rem; margin-top: 0.3rem; display: flex; align-items: center; gap: 0.3rem; } .conversion-detail { font-size: 0.85rem; color: var(--text-secondary); margin-top: 0.8rem; background: #f8fafc; border-radius: 6px; padding: 0.6rem 0.8rem; font-family: 'JetBrains Mono', monospace; } .footer-note { font-size: 0.8rem; color: #64748b; margin-top: 1.5rem; text-align: center; border-top: 1px solid var(--border); padding-top: 1rem; } @media (max-width: 500px) { .container { padding: 1.5rem; } h1 { font-size: 1.5rem; } } </style> </head> <body> <div class="container"> <h1> NAT64 转换器 <span>IPv4 → IPv6</span> </h1> <div class="subtitle"> 基于 nat64.xyz 公共 NAT64 前缀列表 · 实时合成地址 </div> <div class="form-group"> <label for="ipv4Input">IPv4 地址</label> <div class="input-wrapper"> <span class="icon">🌐</span> <input type="text" id="ipv4Input" placeholder="例如 104.21.88.129" value="104.21.88.129" autofocus> </div> </div> <div class="form-group"> <label for="prefixSelect">NAT64 前缀 (Provider / Location)</label> <select id="prefixSelect"> <optgroup label="Kasper Dupont"> <option value="2a00:1098:2b::/96">2a00:1098:2b::/96 – Germany (Nürnberg)</option> <option value="2a00:1098:2c:1::/96">2a00:1098:2c:1::/96 – Germany (Nürnberg)</option> <option value="2a01:4f8:c2c:123f:64::/96">2a01:4f8:c2c:123f:64::/96 – Germany (Nürnberg)</option> <option value="2a01:4f9:c010:3f02:64::/96">2a01:4f9:c010:3f02:64::/96 – Germany (Nürnberg)</option> </optgroup> <optgroup label="level66.services"> <option value="2001:67c:2960:6464::/96" selected>2001:67c:2960:6464::/96 – Anycast (Germany)</option> </optgroup> <optgroup label="Trex"> <option value="2001:67c:2b0:db32:0:1::/96">2001:67c:2b0:db32:0:1::/96 – Finland (Tampere)</option> </optgroup> <optgroup label="ZTVI"> <option value="2602:fc59:b0:64::/96">2602:fc59:b0:64::/96 – USA (Fremont)</option> <option value="2602:fc59:11:64::/96">2602:fc59:11:64::/96 – USA (Chicago)</option> </optgroup> <option value="custom">🔧 自定义前缀 (输入 /96 前缀)</option> </select> </div> <div class="custom-prefix" id="customPrefixWrapper"> <label for="customPrefixInput">自定义 NAT64 前缀 (/96)</label> <div class="input-wrapper"> <span class="icon">🔹</span> <input type="text" id="customPrefixInput" placeholder="例如 2001:db8:abcd:1234::/96"> </div> </div> <div class="result-box"> <div class="result-label">合成的 IPv6 地址</div> <div class="result-ipv6" id="resultIPv6">2001:67c:2960:6464::6815:5881</div> <div class="error-message" id="errorMessage"></div> <div class="conversion-detail" id="detailMapping"></div> </div> <div class="footer-note"> 数据来源 <strong>nat64.xyz</strong> · 十六进制嵌入 (RFC 6052) · 仅供学习与测试 </div> </div> <script> (function() { // DOM 元素 const ipv4Input = document.getElementById('ipv4Input'); const prefixSelect = document.getElementById('prefixSelect'); const customPrefixWrapper = document.getElementById('customPrefixWrapper'); const customPrefixInput = document.getElementById('customPrefixInput'); const resultIPv6 = document.getElementById('resultIPv6'); const errorMessage = document.getElementById('errorMessage'); const detailMapping = document.getElementById('detailMapping'); // 展开 IPv6 地址为 8 个 16-bit 块数组 function expandIPv6(addr) { // 移除可能的 zone ID (%) addr = addr.split('%')[0]; if (addr.includes('::')) { const parts = addr.split('::'); const left = parts[0] ? parts[0].split(':') : []; const right = parts[1] ? parts[1].split(':') : []; const missing = 8 - left.length - right.length; if (missing < 0) return null; // 无效地址 const middle = new Array(missing).fill('0'); const blocks = left.concat(middle, right); return blocks.map(b => parseInt(b || '0', 16)); } else { const blocks = addr.split(':'); if (blocks.length !== 8) return null; return blocks.map(b => parseInt(b || '0', 16)); } } // 压缩 IPv6 地址块数组为字符串 function compressIPv6(blocks) { if (blocks.length !== 8) return null; const strs = blocks.map(b => b.toString(16)); // 寻找最长连续零块 let bestStart = -1, bestLen = 0; let currStart = -1, currLen = 0; for (let i = 0; i < strs.length; i++) { if (strs[i] === '0') { if (currStart === -1) currStart = i; currLen++; } else { if (currLen > bestLen) { bestLen = currLen; bestStart = currStart; } currStart = -1; currLen = 0; } } if (currLen > bestLen) { bestLen = currLen; bestStart = currStart; } if (bestLen < 2) { return strs.join(':'); } const left = strs.slice(0, bestStart); const right = strs.slice(bestStart + bestLen); let result = left.join(':') + '::' + right.join(':'); if (left.length === 0) result = '::' + right.join(':'); if (right.length === 0) result = left.join(':') + '::'; return result; } // 验证并解析 IPv4 地址,返回字节数组或 null function parseIPv4(ipv4) { const parts = ipv4.trim().split('.'); if (parts.length !== 4) return null; const bytes = []; for (let p of parts) { const num = parseInt(p, 10); if (isNaN(num) || num < 0 || num > 255 || p !== num.toString()) return null; bytes.push(num); } return bytes; } // 获取当前选中的前缀字符串(去除 /96) function getCurrentPrefix() { if (prefixSelect.value === 'custom') { let val = customPrefixInput.value.trim(); if (!val) return null; // 允许带 /96 或不带 if (val.endsWith('/96')) val = val.slice(0, -3); return val; } else { let val = prefixSelect.value; if (val.endsWith('/96')) val = val.slice(0, -3); return val; } } // 执行转换并更新界面 function updateConversion() { const ipv4 = ipv4Input.value.trim(); const prefixStr = getCurrentPrefix(); // 清除旧错误 errorMessage.textContent = ''; detailMapping.textContent = ''; if (!ipv4) { resultIPv6.textContent = '请输入 IPv4 地址'; return; } const bytes = parseIPv4(ipv4); if (!bytes) { errorMessage.textContent = '❌ IPv4 地址格式无效,请输入形如 192.0.2.1 的地址'; resultIPv6.textContent = '—'; return; } if (!prefixStr) { errorMessage.textContent = '❌ 请选择或输入有效的 NAT64 前缀'; resultIPv6.textContent = '—'; return; } // 展开前缀 const expanded = expandIPv6(prefixStr); if (!expanded || expanded.length !== 8) { errorMessage.textContent = '❌ IPv6 前缀格式无效或不是 /96 长度'; resultIPv6.textContent = '—'; return; } // IPv4 字节转十六进制组合 const hexParts = bytes.map(b => b.toString(16).padStart(2, '0')); const block6 = parseInt(hexParts[0] + hexParts[1], 16); const block7 = parseInt(hexParts[2] + hexParts[3], 16); // 替换最后两个块 expanded[6] = block6; expanded[7] = block7; const resultAddr = compressIPv6(expanded); resultIPv6.textContent = resultAddr; // 显示转换细节 detailMapping.innerHTML = ` IPv4 十进制: ${bytes.join('.')}<br> 十六进制映射: ${bytes[0]} → 0x${hexParts[0]}, ${bytes[1]} → 0x${hexParts[1]}, ${bytes[2]} → 0x${hexParts[2]}, ${bytes[3]} → 0x${hexParts[3]}<br> 嵌入块: 0x${hexParts[0]}${hexParts[1]} : 0x${hexParts[2]}${hexParts[3]} → <strong>${hexParts[0]}${hexParts[1]}:${hexParts[2]}${hexParts[3]}</strong> `; } // 切换自定义前缀显示 function toggleCustomPrefix() { if (prefixSelect.value === 'custom') { customPrefixWrapper.classList.add('show'); } else { customPrefixWrapper.classList.remove('show'); } updateConversion(); } // 事件监听 ipv4Input.addEventListener('input', updateConversion); prefixSelect.addEventListener('change', toggleCustomPrefix); customPrefixInput.addEventListener('input', updateConversion); // 初始调用 toggleCustomPrefix(); updateConversion(); })(); </script> </body> </html> 3 个帖子 - 2 位参与者 阅读完整话题

IT之家 · 2026-05-23 08:16:47+08:00 · tech

IT之家 5 月 23 日消息,HID Remapper 是一个开源的可编程 USB 输入设备适配器项目,可将手柄输入信号转换为兼容主机的信号。 根据 5 月 20 日发布的最新公告,该项目现已完整支持 Valve Steam 手柄。这意味着 Steam 手柄最受诟病的问题 —— 它只能在 Steam 后台运行的情况下用于 Steam 游戏 —— 得到了彻底解决。 项目开发者 Jack Fedoryński 表示:“所有输入均可使用,包括触控板、触摸传感器以及加速度计 / 陀螺仪。” 除了能够在 Windows 和 Linux 平台上脱离 Steam 后台运行外,这款手柄现在还可兼容 Nintendo Switch、Android 设备以及 Xbox Series X|S 系列主机。 该项目为开源方案,用户可自行在 Github 上获取相关文件并制作 USB 转换器。当然,市面上也有半成品售卖,部分商家报价约 17.5 美元(IT之家注:现汇率约合 119.1 元人民币)。不过,用户可能还需要自行 DIY 一个外壳并刷写固件,才能构成一个完整的成品。 相关阅读: 《 缺乏 XInput 兼容性,Steam Controller 手柄暂未适配 Xbox 游戏库 》

V2EX - 技术 · 2026-05-20 22:14:19+08:00 · tech

最近做了一个有点“奇怪”的工具网站,叫 JustMarkdown 。 开始购买这个域名,没有想到该做什么方向。后来考虑到很多 md to pdf 网站生成的中文,字体不美观,就做了 md to pdf 转换工具,在页面实时渲染真实的打印效果。但后续发现长文本情况下比较卡顿,插入图片支持也不好搞就放弃了。 接下来的转型是做格式转换汇总,支持把 PDF 、Image 、URL 等各种乱七八糟的格式转成 md ,呼应 JustMarkdown 域名,表示只需要 md 就够了。然后在不同的页面分别实现了这些转换工具,希望能抓住一些长尾关键词获取流量,但并没有流量。 最后看到 NotebookLM 和 YouMind 的经典三栏布局,我想所有转换的功能,可以统一在一个 Workspace 页面,然后可以加上 ai chat 和笔记功能,用来深入理解转换后的文本内容。 于是就出现了现在的 JustMarkdown 的功能形态。这个网站和现有的网站已经有很大不同了,但还是一个和 Notion 或 Obsidian 功能重叠的知识库网站。我希望把 JustMarkdown 做的更特别一些。现在市面上的工具都在强调“永久剪藏”,导致我们的 Notion 和 Obsidian 里塞满了“收藏即吃灰”的稍后阅读。JustMarkdown 想做的是反其道而行之:提供一个强迫你消化信息的“中转站”。 把任何格式的复杂文档扔进来转成 Markdown 后,你可以尝试以下这套硬核的阅读方式: 划线与上下文讨论: 网页端实现了类似原生阅读器的体验,鼠标选中文本后会弹出快捷工具栏(支持多种颜色高亮)。你不仅能标记,还能直接基于选中的内容唤起右侧 AI 进行对话,AI 的回答会严格锚定你选中的上下文。 外文/长文的“费曼消化法”: 这是我个人最推荐的使用场景。当你面对一篇晦涩的外文技术文档或长篇研报时: 选中一段难以理解的原文,让右侧的 AI 提供 3 种不同风格的翻译:直译、意译、费曼技巧白话版。 交叉对比这三种解释,提取出最精准的核心意思。 在左侧的工作区用你自己的大白话把结论写成新的 MD 笔记。 最后的一步:直接把左侧原文里的那一段删掉( Delete )。 通过这种“看懂一段,总结一段,删掉一段”的破坏性阅读,一篇冗长复杂的文档最终会被你物理意义上地“啃”完,最后只留下一篇高度浓缩、完全属于你个人理解的精华笔记。这时候你就可以把笔记带走,原始文档直接“阅后即焚”。 为什么要做成这样? 我高中时有很多练习题要做,然后要复习错题。我当时就会把错题抄到笔记本,然后把原来的练习题用笔涂掉。我不愿意看着那些已经做过的题目,因为那样会让我觉得有负担。 体验地址: justmarkdown.com 。 目前网站还在早期高频迭代阶段。大家对这种工作流有什么看法,欢迎在帖子里交流!

V2EX - 技术 · 2026-05-20 22:14:19+08:00 · tech

最近做了一个有点“奇怪”的工具网站,叫 JustMarkdown 。 开始购买这个域名,没有想到该做什么方向。后来考虑到很多 md to pdf 网站生成的中文,字体不美观,就做了 md to pdf 转换工具,在页面实时渲染真实的打印效果。但后续发现长文本情况下比较卡顿,插入图片支持也不好搞就放弃了。 接下来的转型是做格式转换汇总,支持把 PDF 、Image 、URL 等各种乱七八糟的格式转成 md ,呼应 JustMarkdown 域名,表示只需要 md 就够了。然后在不同的页面分别实现了这些转换工具,希望能抓住一些长尾关键词获取流量,但并没有流量。 最后看到 NotebookLM 和 YouMind 的经典三栏布局,我想所有转换的功能,可以统一在一个 Workspace 页面,然后可以加上 ai chat 和笔记功能,用来深入理解转换后的文本内容。 于是就出现了现在的 JustMarkdown 的功能形态。这个网站和现有的网站已经有很大不同了,但还是一个和 Notion 或 Obsidian 功能重叠的知识库网站。我希望把 JustMarkdown 做的更特别一些。现在市面上的工具都在强调“永久剪藏”,导致我们的 Notion 和 Obsidian 里塞满了“收藏即吃灰”的稍后阅读。JustMarkdown 想做的是反其道而行之:提供一个强迫你消化信息的“中转站”。 把任何格式的复杂文档扔进来转成 Markdown 后,你可以尝试以下这套硬核的阅读方式: 划线与上下文讨论: 网页端实现了类似原生阅读器的体验,鼠标选中文本后会弹出快捷工具栏(支持多种颜色高亮)。你不仅能标记,还能直接基于选中的内容唤起右侧 AI 进行对话,AI 的回答会严格锚定你选中的上下文。 外文/长文的“费曼消化法”: 这是我个人最推荐的使用场景。当你面对一篇晦涩的外文技术文档或长篇研报时: 选中一段难以理解的原文,让右侧的 AI 提供 3 种不同风格的翻译:直译、意译、费曼技巧白话版。 交叉对比这三种解释,提取出最精准的核心意思。 在左侧的工作区用你自己的大白话把结论写成新的 MD 笔记。 最后的一步:直接把左侧原文里的那一段删掉( Delete )。 通过这种“看懂一段,总结一段,删掉一段”的破坏性阅读,一篇冗长复杂的文档最终会被你物理意义上地“啃”完,最后只留下一篇高度浓缩、完全属于你个人理解的精华笔记。这时候你就可以把笔记带走,原始文档直接“阅后即焚”。 为什么要做成这样? 我高中时有很多练习题要做,然后要复习错题。我当时就会把错题抄到笔记本,然后把原来的练习题用笔涂掉。我不愿意看着那些已经做过的题目,因为那样会让我觉得有负担。 体验地址: justmarkdown.com 。 目前网站还在早期高频迭代阶段。大家对这种工作流有什么看法,欢迎在帖子里交流!

V2EX - 技术 · 2026-05-20 21:14:19+08:00 · tech

最近做了一个有点“奇怪”的工具网站,叫 JustMarkdown 。 开始购买这个域名,没有想到该做什么方向。后来考虑到很多 md to pdf 网站生成的中文,字体不美观,就做了 md to pdf 转换工具,在页面实时渲染真实的打印效果。但后续发现长文本情况下比较卡顿,插入图片支持也不好搞就放弃了。 接下来的转型是做格式转换汇总,支持把 PDF 、Image 、URL 等各种乱七八糟的格式转成 md ,呼应 JustMarkdown 域名,表示只需要 md 就够了。然后在不同的页面分别实现了这些转换工具,希望能抓住一些长尾关键词获取流量,但并没有流量。 最后看到 NotebookLM 和 YouMind 的经典三栏布局,我想所有转换的功能,可以统一在一个 Workspace 页面,然后可以加上 ai chat 和笔记功能,用来深入理解转换后的文本内容。 于是就出现了现在的 JustMarkdown 的功能形态。这个网站和现有的网站已经有很大不同了,但还是一个和 Notion 或 Obsidian 功能重叠的知识库网站。我希望把 JustMarkdown 做的更特别一些。现在市面上的工具都在强调“永久剪藏”,导致我们的 Notion 和 Obsidian 里塞满了“收藏即吃灰”的稍后阅读。JustMarkdown 想做的是反其道而行之:提供一个强迫你消化信息的“中转站”。 把任何格式的复杂文档扔进来转成 Markdown 后,你可以尝试以下这套硬核的阅读方式: 划线与上下文讨论: 网页端实现了类似原生阅读器的体验,鼠标选中文本后会弹出快捷工具栏(支持多种颜色高亮)。你不仅能标记,还能直接基于选中的内容唤起右侧 AI 进行对话,AI 的回答会严格锚定你选中的上下文。 外文/长文的“费曼消化法”: 这是我个人最推荐的使用场景。当你面对一篇晦涩的外文技术文档或长篇研报时: 选中一段难以理解的原文,让右侧的 AI 提供 3 种不同风格的翻译:直译、意译、费曼技巧白话版。 交叉对比这三种解释,提取出最精准的核心意思。 在左侧的工作区用你自己的大白话把结论写成新的 MD 笔记。 最后的一步:直接把左侧原文里的那一段删掉( Delete )。 通过这种“看懂一段,总结一段,删掉一段”的破坏性阅读,一篇冗长复杂的文档最终会被你物理意义上地“啃”完,最后只留下一篇高度浓缩、完全属于你个人理解的精华笔记。这时候你就可以把笔记带走,原始文档直接“阅后即焚”。 为什么要做成这样? 我高中时有很多练习题要做,然后要复习错题。我当时就会把错题抄到笔记本,然后把原来的练习题用笔涂掉。我不愿意看着那些已经做过的题目,因为那样会让我觉得有负担。 体验地址: justmarkdown.com 。 目前网站还在早期高频迭代阶段。大家对这种工作流有什么看法,欢迎在帖子里交流!

linux.do · 2026-04-26 15:16:23+08:00 · tech

本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 之前提交作业,因为是在 Obsidian 上面写的,所以是 markdown 格式,但是要求提交 PDF……在网上找了一些格式转换器,但效果都不是很好,不是这里有格式错误,就是那里有黑色小方块的出现(绷)。 最后自己痛定思痛,选择自己做一个像样的转换器(乐)(增加了一大堆的工作量,还给自己整破防了)。 先给佬们看看想法(同时主动承认自己是用 Codex 在做开发,各位老师们我对不起你们,你们教的古法编程太难用了呜呜呜呜呜) 这个是目标的格式,希望做相互转换。 打算采用非热门格式转换需下载对应插件,可随时删减的形式降低资源占用。 超大文件采用动态分割,子部分分别做转换后进行合并,并对格式进行检查与修改。 文档也写了很多,只是现在不知道这个项目能不能做下去,还有就是这个项目到底有没有意义,害怕浪费时间(呜呜呜)。 求佬们的指点迷津。 附上 Github 仓库链接: github.com GitHub - Vantalens/Trans2Former: A browser-native document transformation engine... A browser-native document transformation engine that converts and restructures multi-format content via a unified DocumentModel. 2 个帖子 - 2 位参与者 阅读完整话题