跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 多项式曲线拟合实战:从理论到工程落地

多项式曲线拟合是数据分析中的关键统计方法,旨在通过构建数学模型来逼近给定数据点。本文基于 C++ 结合 Eigen 库,深入讲解二维平面上的多项式拟合实现。核心采用最小二乘法优化系数,涵盖范德蒙矩阵构建、正规方程推导、数值稳定性处理(如归一化、SVD 分解)、异常值剔除及模型诊断等工程实践。文章强调偏差 - 方差权衡与过拟合风险,提供从理论到代码落地的完整路径,适用于趋势预测与建模分析场景。

赛博朋克发布于 2026/3/22更新于 2026/7/2152 浏览

C++ 多项式曲线拟合实战:从理论到工程落地

引言

你有没有遇到过这样的场景?传感器采集了一堆数据点,杂乱无章地散落在坐标系里。老板拍着桌子问:'这背后到底是什么规律?'——而你盯着屏幕,脑子里只有一个念头:得找个函数把这些点串起来。

这,就是曲线拟合的起点。

在真实世界中,我们几乎永远无法获得完美的函数表达式。物理实验、金融走势、机器学习特征……一切依赖数据驱动的领域,都建立在一个共同前提上:用一个简洁的数学模型去逼近复杂的现实。 而多项式拟合,正是这个过程最基础也最关键的工具之一。

但问题来了:怎么选阶数?为什么最小二乘法总是在平方误差上做文章?直接求解正规方程会不会翻车?今天,我们就来一次'开箱即用'的深度拆解,把从原始数据到最终模型的每一步,都掰开了揉碎了讲清楚。

准备好了吗?咱们不走寻常路,也不念教科书——这次是工程师之间的对话 🛠️。


多项式建模:不只是个公式,而是对自由度的掌控

先别急着写代码。让我们回到那个最朴素的问题:为什么要用多项式?

答案其实很反直觉:因为它'看起来非线性',但'算起来却是线性的'。

听上去像绕口令?举个例子你就懂了。

假设我们要拟合的数据满足这样一个关系:

$$ f(x) = a_0 + a_1 x + a_2 x^2 + \cdots + a_n x^n $$

这个函数整体上看当然是非线性的——毕竟有 $x^2$、$x^3$ 甚至更高次幂。可注意!它对参数 $\mathbf{a} = [a_0, a_1, …, a_n]^T$ 的依赖却是完全线性的。也就是说,无论 $x$ 怎么变,只要我把所有 $x^k$ 看作已知量,那整个问题就变成了:

'找一组系数 $a_k$,让它们和对应的 $x^k$ 相乘后加起来,尽量接近观测值。'

是不是突然觉得轻松多了?

这种'形非线,实为线'的特性,是多项式能在科学计算中屹立不倒的根本原因。魏尔斯特拉斯逼近定理告诉我们:任何连续函数都可以被多项式以任意精度逼近。换句话说,只要你愿意提高阶数,就能无限贴近真实规律(当然,代价可能是灾难性的过拟合 😬)。

范德蒙矩阵:把离散数据变成代数语言

现在我们有一组数据 $(x_i, y_i)$,共 $m$ 个点。要把上面那个理想化的公式落地成可计算的形式,第一步就是构造所谓的范德蒙矩阵(Vandermonde Matrix)。

它的结构长这样:

$$ \mathbf{X} = \begin{bmatrix} 1 & x_1 & x_1^2 & \cdots & x_1^n \ 1 & x_2 & x_2^2 & \cdots & x_2^n \ \vdots & \vdots & \vdots & \ddots & \vdots \ 1 & x_m & x_m^2 & \cdots & x_m^n \end{bmatrix} $$

每一行对应一个数据点,每一列代表一个幂次项。这个矩阵一旦建成,原始数据就完成了从'物理测量'到'数学对象'的跃迁。后续所有的运算都将在这个框架下进行。

来看一段 C++ 实现:

std::vector<std::vector<double>> buildVandermonde(const std::vector<double>& x, int degree) {
    int m = x.size();
    int n = degree + 1;
    std::vector<std::vector<double>> X(m, std::vector<double>(n));
    for (int i = ; i < m; ++i) {
         ( j = ; j < n; ++j) {
            X[i][j] = std::(x[i], j);
        }
    }
     X;
}
0
for
int
0
pow
return

看似简单,但这里埋着一个大坑:当 $x_i$ 比较大时(比如大于 5),高阶项如 $x_i^{10}$ 可能达到 $10^7$ 甚至更高,导致矩阵元素数量级差异巨大。数值分析里管这叫'病态矩阵',轻则结果不准,重则直接崩溃。

解决办法?归一化先行 ⚠️!

graph TD
    A[原始数据点 xi, yi] --> B{是否需要预处理?}
    B -->|是 | C[归一化/去噪]
    B -->|否 | D[直接构造矩阵]
    C --> D
    D --> E[初始化空矩阵 X]
    E --> F[遍历每个 xi]
    F --> G[计算 1, xi, xi², ..., xin]
    G --> H[填入矩阵第 i 行]
    H --> I{是否所有点处理完毕?}
    I -->|否 | F
    I -->|是 | J[输出范德蒙矩阵 X]

这套流程图看着平淡无奇,实则是工业级系统和玩具代码的本质区别。真正的鲁棒性,从来不是靠运气维持的。

阶数选择的艺术:偏差 - 方差的永恒博弈

很多人以为,拟合效果好不好,全看阶数够不够高。错!

现实中更常见的情况是:阶数越高,训练误差越低,但预测能力反而下降。

这就是著名的'偏差 - 方差权衡'问题。

模型类型偏差方差表现
低阶(如线性)高低欠拟合,错过趋势
中阶(如 3~6 次)适中适中最佳平衡区
高阶(>8 次)低高过拟合,记住噪声

我们可以用 Python 快速验证这一点:

import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

np.random.seed(42)
x = np.linspace(0, 3, 30)
y_true = 2 * x**2 - 3 * x + 1
y_noisy = y_true + np.random.normal(0, 0.5, size=x.shape)

train_errors = []
val_errors = []
degrees = range(1, 10)

for d in degrees:
    poly = PolynomialFeatures(degree=d)
    X_poly = poly.fit_transform(x.reshape(-1, 1))
    idx_train = np.random.choice(len(x), size=20, replace=False)
    idx_val = np.setdiff1d(np.arange(len(x)), idx_train)
    reg = LinearRegression().fit(X_poly[idx_train], y_noisy[idx_train])
    y_train_pred = reg.predict(X_poly[idx_train])
    y_val_pred = reg.predict(X_poly[idx_val])
    train_errors.append(mean_squared_error(y_noisy[idx_train], y_train_pred))
    val_errors.append(mean_squared_error(y_noisy[idx_val], y_val_pred))
# 绘图观察 U 型曲线

运行之后你会发现:验证误差先降后升,形成一个漂亮的 U 型曲线。最低点对应的阶数,才是真正的'最优解'。

如果你不想手动调参,可以用信息准则自动判断:

$$ \text{AIC} = 2k - 2\ln(L),\quad \text{BIC} = k\ln(m) - 2\ln(L) $$

其中 $k = n+1$ 是参数个数,$L$ 是似然函数最大值。两者都会惩罚复杂模型,帮你避免掉进'过度追求完美拟合'的陷阱。


最小二乘法:优雅背后的数学逻辑

如果说多项式是建模的语言,那么最小二乘法就是推理的引擎。

它的思想极其朴素:让预测值和真实值之间的总体偏差尽可能小。

但偏差有正有负,直接求和会相互抵消。怎么办?平方!

于是目标函数成了:

$$ S(\mathbf{a}) = \sum_{i=1}^m \left( y_i - \sum_{k=0}^n a_k x_i^k \right)^2 = | \mathbf{Y} - \mathbf{X}\mathbf{a} |^2 $$

这个目标函数的设计堪称精妙:

  • 平方放大显著误差的影响,迫使算法优先修正大偏离;
  • 数学上光滑可导,方便梯度下降等优化方法介入;
  • 在误差服从正态分布的前提下,等价于最大似然估计。

正规方程推导:微积分遇上线性代数

为了最小化 $S(\mathbf{a})$,我们对每个 $a_j$ 求偏导并令其为零:

$$ \frac{\partial S}{\partial a_j} = -2 \sum_{i=1}^m \left( y_i - \sum_{k=0}^n a_k x_i^k \right) x_i^j = 0 $$

整理一下得到:

$$ \sum_{k=0}^n a_k \left( \sum_{i=1}^m x_i^{k+j} \right) = \sum_{i=1}^m y_i x_i^j $$

这其实就是:

$$ \mathbf{X}^T \mathbf{X} \mathbf{a} = \mathbf{X}^T \mathbf{Y} $$

也就是传说中的正规方程(Normal Equations)。

最终解为:

$$ \mathbf{a} = (\mathbf{X}^T \mathbf{X})^{-1} \mathbf{X}^T \mathbf{Y} $$

是不是很简洁?但别高兴太早——这个公式的美丽外表下藏着致命弱点。

符号名称维度构造方式
$\mathbf{X}$设计矩阵$m \times (n+1)$范德蒙结构
$\mathbf{X}^T \mathbf{X}$Gram 矩阵$(n+1) \times (n+1)$内积形成的对称正定矩阵
$\mathbf{X}^T \mathbf{Y}$观测投影向量$(n+1) \times 1$数据与基函数的交叉内积
$(\mathbf{X}^T \mathbf{X})^{-1}$协方差矩阵缩放因子$(n+1) \times (n+1)$决定参数估计精度

看到没?中间那个 $(\mathbf{X}^T \mathbf{X})$ 很容易变得'又扁又长',条件数爆炸。一旦如此,哪怕输入数据有一点点扰动,输出系数就会剧烈震荡。

来看 Eigen 库的实现:

#include <Eigen/Dense>

Eigen::VectorXd solve_normal_equation(const Eigen::MatrixXd& X, const Eigen::VectorXd& Y) {
    Eigen::MatrixXd XtX = X.transpose() * X;
    Eigen::VectorXd XtY = X.transpose() * Y;
    return XtX.ldlt().solve(XtY); // 使用 LDLT 分解提升稳定性
}

用了 .ldlt() 而不是显式求逆,已经算是进步了。但在实际项目中,我还是建议:能不用正规方程就不用。尤其是当你面对的是传感器数据、金融时间序列这类'脏'数据时,数值稳定性比速度更重要。

凸优化视角:为什么你能相信这个解?

也许你会问:我凭什么相信这个解是最优的?

答案藏在凸优化里。

最小二乘的目标函数是一个关于 $\mathbf{a}$ 的二次函数,其 Hessian 矩阵为 $2\mathbf{X}^T\mathbf{X}$。只要 $\mathbf{X}$ 列满秩,$\mathbf{X}^T\mathbf{X}$ 就是正定的,意味着目标函数严格凸。

这意味着什么?

  • 存在唯一的全局最小值;
  • 所有局部极小点都是全局最优;
  • 梯度类算法一定能收敛到同一结果。

所以,只要你的设计矩阵没问题,这个解就是可靠的 ✅。

graph LR
    P[最小二乘问题] --> Q{X 是否列满秩?}
    Q -->|是 | R[XtX 正定 → 凸函数]
    Q -->|否 | S[存在无穷多解或无解]
    R --> T[梯度为零 ⇒ 唯一最优解]
    S --> U[需引入正则化或 SVD]

这张流程图值得贴在工位上。每次你想强行拟合一堆可疑数据前,先问问自己:我的矩阵满秩吗?


数据处理实战:让理论真正跑起来

再完美的理论,碰上垃圾数据也会崩盘。真正的高手,从来不迷信公式,而是靠一套完整的预处理流水线保驾护航。

文件读取:别让格式毁了你的努力

想象一下:你辛辛苦苦写了几百行代码,结果因为 CSV 文件里多了一个空格,程序直接报错退出。这种事情,在新手身上天天发生。

所以我们需要一个健壮的文件解析器:

bool read_csv(const std::string& filename, std::vector<double>& x_vec, std::vector<double>& y_vec) {
    std::ifstream file(filename);
    if (!file.is_open()) {
        throw std::runtime_error("Cannot open file: " + filename);
    }
    std::string line;
    int line_num = 0;
    while (std::getline(file, line)) {
        ++line_num;
        std::istringstream ss(line);
        std::string cell_x, cell_y;
        if (!std::getline(ss, cell_x, ',')) continue;
        if (!std::getline(ss, cell_y, ',')) {
            throw std::invalid_argument("Incomplete data at line " + std::to_string(line_num));
        }
        try {
            double x = std::stod(cell_x);
            double y = std::stod(cell_y);
            x_vec.push_back(x);
            y_vec.push_back(y);
        } catch (...) {
            throw std::invalid_argument("Invalid number format at line " + std::to_string(line_num));
        }
    }
    if (x_vec.empty()) {
        throw std::length_error("No valid data found in file.");
    }
    return true;
}

关键点在于:

  • 明确定位错误位置(第几行);
  • 捕获异常并转换为有意义的提示;
  • 防止空数据导致后续崩溃。

这才是生产级代码应有的样子。

异常值剔除:别让 outliers 毁了整锅汤

现实中的数据,总有几个'叛逆分子'不肯听话。它们可能是传感器瞬时故障、人为录入错误,或者是极端事件。不管原因如何,它们的存在会让拟合结果严重偏离。

常用方法有两个:Z-score 和 IQR。

前者适合正态分布数据,后者更鲁棒。推荐使用 IQR:

void remove_outliers_iqr(std::vector<double>& x_data, std::vector<double>& y_data) {
    if (y_data.size() < 4) return;
    std::vector<double> y_sorted = y_data;
    std::sort(y_sorted.begin(), y_sorted.end());
    double Q1 = percentile(y_sorted, 0.25);
    double Q3 = percentile(y_sorted, 0.75);
    double IQR = Q3 - Q1;
    double lower_bound = Q1 - 1.5 * IQR;
    double upper_bound = Q3 + 1.5 * IQR;
    std::vector<double> new_x, new_y;
    for (size_t i = 0; i < y_data.size(); ++i) {
        if (y_data[i] >= lower_bound && y_data[i] <= upper_bound) {
            new_x.push_back(x_data[i]);
            new_y.push_back(y_data[i]);
        }
    }
    x_data = std::move(new_x);
    y_data = std::move(new_y);
}

注意用了 std::move,避免深层拷贝带来的性能损耗。现代 C++ 的移动语义,是高效编程的必备技能。

归一化:拯救病态矩阵的最后一道防线

前面说过,范德蒙矩阵天生容易病态。解决方案也很明确:归一化输入变量。

标准做法是 Z-score 标准化:

$$ x' = \frac{x - \mu_x}{\sigma_x} $$

C++ 实现如下:

void normalize_data(std::vector<double>& x_data) {
    double sum = 0.0;
    for (double x : x_data) sum += x;
    double mean = sum / x_data.size();
    double var_sum = 0.0;
    for (double x : x_data) var_sum += (x - mean) * (x - mean);
    double stddev = std::sqrt(var_sum / x_data.size());
    if (stddev == 0.0) stddev = 1.0;
    for (double& x : x_data) {
        x = (x - mean) / stddev;
    }
}

但这一步有个大坑:你必须保存 $\mu_x$ 和 $\sigma_x$!否则后续无法将拟合结果反变换回原始坐标系。

记住:归一化是为了计算稳定,不是为了改变物理意义。


高效求解策略:不只是快,更是稳

到了这一步,你已经有了干净的数据、合理的阶数、稳定的矩阵。接下来,就是见证奇迹的时刻:求解线性系统。

高斯消元:教学经典 vs 实战局限

高斯消元是教科书里的常客,原理简单直观。以下是部分主元版本的实现:

Vector gaussian_elimination(Matrix A, Vector b) {
    int n = A.size();
    for (int i = 0; i < n; ++i) A[i].push_back(b[i]);
    for (int k = 0; k < n; ++k) {
        int max_row = k;
        for (int i = k + 1; i < n; ++i)
            if (abs(A[i][k]) > abs(A[max_row][k])) max_row = i;
        swap(A[k], A[max_row]);
        for (int i = k + 1; i < n; ++i) {
            double factor = A[i][k] / A[k][k];
            for (int j = k; j <= n; ++j) A[i][j] -= factor * A[k][j];
        }
    }
    Vector x(n);
    for (int i = n - 1; i >= 0; --i) {
        x[i] = A[i][n];
        for (int j = i + 1; j < n; ++j) x[i] -= A[i][j] * x[j];
        x[i] /= A[i][i];
    }
    return x;
}

中小规模($n<50$)还能应付,但面对真实工业数据时,效率和稳定性都不够看。

SVD:终极武器,专治各种不服

当矩阵接近奇异、多重共线性严重、或者根本秩亏时,SVD 是唯一靠谱的选择。

其核心思想是分解:

$$ \mathbf{V} = \mathbf{U} \boldsymbol{\Sigma} \mathbf{V}^T $$

则最小二乘解为:

$$ \mathbf{a} = \mathbf{V} \boldsymbol{\Sigma}^{-1} \mathbf{U}^T \mathbf{y} $$

其中可以设置小奇异值为零,抑制噪声放大。

Eigen 中只需一行:

Eigen::JacobiSVD<Eigen::MatrixXd> svd(V, Eigen::ComputeThinU | Eigen::ComputeThinV);
return svd.solve(y);

虽然耗时稍长,但它能在其他方法失败的地方成功,堪称'保命技'。

flowchart TD
    Start[开始求解] --> IsStable{矩阵是否良态?}
    IsStable -- 是 --> UseQR[使用 QR 分解]
    IsStable -- 否 --> UseSVD[使用 SVD 分解]
    UseQR --> Result1[快速获得近似解]
    UseSVD --> Result2[获得最稳健解]
    Result1 --> End
    Result2 --> End

聪明的做法是根据条件数动态切换求解器。这才是智能系统的雏形。


完整系统集成:从命令行到可视化

最后,让我们把这些模块组装成一个可用的工具。

模块化设计:CurveFitter 类登场

class CurveFitter {
private:
    std::vector<double> x, y;
    Eigen::VectorXd coefficients;
    int degree;
public:
    CurveFitter(const std::vector<double>& x_data, const std::vector<double>& y_data, int deg)
        : x(x_data), y(y_data), degree(deg) {}
    void build_vandermonde_matrix(Eigen::MatrixXd& V);
    bool solve_normal_equations();
    double evaluate(double x_val) const;
    double compute_rmse() const;
    double compute_r_squared() const;
    void save_results(const std::string& output_path) const;
};

RAII + Eigen 的组合拳,既保证资源安全,又获得极致性能。

命令行交互:让用户掌控节奏

while ((opt = getopt(argc, argv, "i:d:o:h")) != -1) {
    switch (opt) {
        case 'i': input_file = optarg; break;
        case 'd': degree = atoi(optarg); break;
        case 'o': output_file = optarg; break;
        case 'h': cout << "Usage: " << argv[0] << " -i data.txt -d 3 -o result.csv" << endl; return 0;
    }
}

支持 -i, -d, -o 参数,无需修改代码即可批量运行不同配置,非常适合自动化测试。

自动绘图:一键生成图表

输出 CSV 文件供 Gnuplot 使用:

set title "Polynomial Fit (degree $1)"
set xlabel "x"
set ylabel "y"
set grid
set terminal png size 800,600
set output 'fit_plot.png'
plot '$2' using 1:2 with points pt 7 ps 0.8 title "Data", \
     '$2' using 1:3 with lines lw 2 title "Fitted Curve"

C++ 中调用:

std::system("gnuplot plot.gp");

从此告别手动画图,真正实现'一键出报告'🎯。


模型诊断:防止自我欺骗的关键一步

最后提醒一句:不要盲目相信你的拟合结果。

系统应具备基本的自检能力:

if (degree >= 8 && rmse_on_test_region > 2 * global_rmse) {
    std::cout << "[Warning] Possible overfitting detected. "
              << "Consider reducing polynomial degree." << std::endl;
}
double r2 = fitter.compute_r_squared();
if (r2 < 0.8) {
    std::cout << "[Suggestion] Low R² (" << r2 << "). Model may underfit. Try higher degree or check data noise." << std::endl;
}

还可以预留接口引入正则化:

Eigen::MatrixXd regularized_A = V.transpose() * V + lambda * Eigen::MatrixXd::Identity(degree+1, degree+1);
coefficients = regularized_A.ldlt().solve(V.transpose() * y_vector);

岭回归虽简单,却能在关键时刻救你一命。


写在最后:拟合不仅是技术,更是思维方式

回过头看,曲线拟合这件事,本质上是一场在有限信息中寻找秩序的努力。

我们用多项式作为语言,用最小二乘作为推理规则,用正则化作为防错机制。每一步都在平衡:表达力 vs 稳定性,拟合优度 vs 泛化能力,速度 vs 精度。

而这,也正是所有数据科学工作的缩影。

下次当你面对一堆混乱的数据时,不妨问问自己:

我是真的发现了规律,还是只是记住了噪声?

毕竟,最好的模型,往往不是最复杂的那个,而是最能经得起质疑的那个 💡。

目录

  1. C++ 多项式曲线拟合实战:从理论到工程落地
  2. 引言
  3. 多项式建模:不只是个公式,而是对自由度的掌控
  4. 范德蒙矩阵:把离散数据变成代数语言
  5. 阶数选择的艺术:偏差 - 方差的永恒博弈
  6. 绘图观察 U 型曲线
  7. 最小二乘法:优雅背后的数学逻辑
  8. 正规方程推导:微积分遇上线性代数
  9. 凸优化视角:为什么你能相信这个解?
  10. 数据处理实战:让理论真正跑起来
  11. 文件读取:别让格式毁了你的努力
  12. 异常值剔除:别让 outliers 毁了整锅汤
  13. 归一化:拯救病态矩阵的最后一道防线
  14. 高效求解策略:不只是快,更是稳
  15. 高斯消元:教学经典 vs 实战局限
  16. SVD:终极武器,专治各种不服
  17. 完整系统集成:从命令行到可视化
  18. 模块化设计:CurveFitter 类登场
  19. 命令行交互:让用户掌控节奏
  20. 自动绘图:一键生成图表
  21. 模型诊断:防止自我欺骗的关键一步
  22. 写在最后:拟合不仅是技术,更是思维方式
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Spring Cloud Gateway 微服务统一入口实战
  • 基于 Java 的百度地图路线规划服务开发指南
  • 工程项目管理系统技术架构与核心功能梳理
  • IntelliJ IDEA 搭建 Spring Boot Web 项目实战指南
  • Linux 系统编程入门:前世今生与内核发展史
  • AI 无人机智慧巡检平台:20+ 场景识别与全流程调度方案
  • C++ 笔试算法实战:打怪、字符串分类与城市群计数
  • OpenCode 开源 AI 编程助手实战指南
  • Java LangChain4j 核心实战与集成指南
  • 被工具定义的编程时代:VS Code 与 JetBrains 效率指南
  • RabbitMQ 高级特性:消息与队列 TTL 设置详解
  • 支持 Nor Flash 读写的 SPI 主控制器设计、仿真和 FPGA 验证(含 XIP 模式)
  • LLM 大模型实践指南:从入门到应用开发路线
  • C++ 核心概念:引用、内联与 nullptr 解析
  • Ollama 本地 CPU 部署开源大模型指南
  • uv 虚拟环境管理:创建、激活与 Python 版本指定
  • 分布式光纤声波传感(DAS)在无人机入侵探测中的应用
  • C++ 算法题:统计满足异或和等于和的子数组数量
  • Python Emoji 库使用教程
  • 基于 OpenClaw 与 Claude 的自动化写作工作流搭建

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online