上篇文章,我们用 Qt5 实现了在小工具箱中添加了《XML文本格式化功能》功能。为了继续丰富我们的工具箱,今天我们就再增加一个平时经常用到的功能吧,就是「 Base64加解密
」功能。下面我们就来看看如何来规划开发一个这样的小功能并且添加到我们的工具箱中吧。
老规矩,先看效果
Base64加解密功能概述
Base64 加解密功能的设计旨在提供对文本进行编码和解码的便捷方式。Base64 是一种将二进制数据转换为文本数据的编码方法,通常用于在网络通信中传输二进制数据,也常被用于简单加密。
功能概述:
-
加密(Base64 编码):
- 输入框: 用户输入待加密的文本。
- 加密按钮: 触发对输入文本进行 Base64 编码的操作。
- 输出框: 显示输入文本的 Base64 编码结果。
-
解密(Base64 解码):
- 输入框: 用户输入待解密的 Base64 字符串。
- 解密按钮: 触发对输入的 Base64 字符串进行解码的操作。
- 输出框: 显示 Base64 字符串的解码结果,即原始文本内容。
功能需求:
- 直观性: 提供清晰的用户界面,使用户能够方便地输入文本、执行加密和解密操作,并直观地查看结果。
- 互操作性: 允许用户轻松地将文本数据进行编码和解码,确保输入输出间的正确转换。
- 易用性: 简化用户操作流程,确保功能操作简单易懂,避免复杂性和混淆。
该功能有助于用户快速进行文本编码和解码,方便地在需要时将文本转换为 Base64 编码或将 Base64 编码转换回原始文本。
核心代码实现
class Base64Converter : public QWidget {
Q_OBJECT
public:
explicit Base64Converter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new QTextEdit(this);
layout->addWidget(inputTextEdit);
encryptButton = new QPushButton("加密", this);
connect(encryptButton, &QPushButton::clicked, this, &Base64Converter::encryptText);
layout->addWidget(encryptButton);
decryptButton = new QPushButton("解密", this);
connect(decryptButton, &QPushButton::clicked, this, &Base64Converter::decryptText);
layout->addWidget(decryptButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
private slots:
void encryptText() {
QString inputText = inputTextEdit->toPlainText().toUtf8();
QByteArray byteArray = inputText.toUtf8().toBase64();
outputTextEdit->setText(byteArray);
}
void decryptText() {
QString inputText = inputTextEdit->toPlainText();
QByteArray byteArray = QByteArray::fromBase64(inputText.toUtf8());
outputTextEdit->setText(byteArray);
}
private:
QTextEdit *inputTextEdit;
QTextEdit *outputTextEdit;
QPushButton *encryptButton;
QPushButton *decryptButton;
};
核心代码拆分讲解
这个功能特别适合练手,因为实现起来很简单。😄
class Base64Converter : public QWidget {
Q_OBJECT
public:
explicit Base64Converter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new QTextEdit(this);
layout->addWidget(inputTextEdit);
encryptButton = new QPushButton("加密", this);
connect(encryptButton, &QPushButton::clicked, this, &Base64Converter::encryptText);
layout->addWidget(encryptButton);
decryptButton = new QPushButton("解密", this);
connect(decryptButton, &QPushButton::clicked, this, &Base64Converter::decryptText);
layout->addWidget(decryptButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
这里定义了一个名为 Base64Converter
的类,继承自 QWidget
。构造函数中创建了一个垂直布局,并初始化了输入框 inputTextEdit
、加密按钮 encryptButton
、解密按钮 decryptButton
和输出框 outputTextEdit
。每个控件都被添加到布局中,并且设置了布局。
private slots:
void encryptText() {
QString inputText = inputTextEdit->toPlainText().toUtf8();
QByteArray byteArray = inputText.toUtf8().toBase64();
outputTextEdit->setText(byteArray);
}
这个 encryptText()
槽函数是在点击加密按钮时触发的。它从输入文本框 inputTextEdit
中获取文本,并将其转换为 UTF-8 编码的字符串。接着,使用 toBase64()
函数对该字符串进行 Base64 编码,并将结果设置到输出文本框 outputTextEdit
中。
void decryptText() {
QString inputText = inputTextEdit->toPlainText();
QByteArray byteArray = QByteArray::fromBase64(inputText.toUtf8());
outputTextEdit->setText(byteArray);
}
另一个槽函数 decryptText()
是解密的逻辑。它从输入框获取 Base64 编码的文本,然后使用 fromBase64()
函数对其进行解码。解码后的结果以字符串形式设置到输出文本框中。这两个槽函数实现了加密和解密的功能。
讲解完毕,下面是完整代码,复制到本地跑一跑吧~
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QDebug>
#include <QListWidget>
#include <QClipboard>
#include <QMimeData>
#include <QTextEdit>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QXmlStreamReader>
#define myApp (dynamic_cast<QApplication *>(QCoreApplication::instance()))
class Base64Converter : public QWidget {
Q_OBJECT
public:
explicit Base64Converter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new QTextEdit(this);
layout->addWidget(inputTextEdit);
encryptButton = new QPushButton("加密", this);
connect(encryptButton, &QPushButton::clicked, this, &Base64Converter::encryptText);
layout->addWidget(encryptButton);
decryptButton = new QPushButton("解密", this);
connect(decryptButton, &QPushButton::clicked, this, &Base64Converter::decryptText);
layout->addWidget(decryptButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
private slots:
void encryptText() {
QString inputText = inputTextEdit->toPlainText().toUtf8();
QByteArray byteArray = inputText.toUtf8().toBase64();
outputTextEdit->setText(byteArray);
}
void decryptText() {
QString inputText = inputTextEdit->toPlainText();
QByteArray byteArray = QByteArray::fromBase64(inputText.toUtf8());
outputTextEdit->setText(byteArray);
}
private:
QTextEdit *inputTextEdit;
QTextEdit *outputTextEdit;
QPushButton *encryptButton;
QPushButton *decryptButton;
};
class XmlFormatter : public QWidget {
Q_OBJECT
public:
explicit XmlFormatter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new QTextEdit(this);
layout->addWidget(inputTextEdit);
formatButton = new QPushButton("格式化 XML", this);
connect(formatButton, &QPushButton::clicked, this, &XmlFormatter::formatXml);
layout->addWidget(formatButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
private slots:
void formatXml() {
// 获取输入的XML文本
QString inputText = inputTextEdit->toPlainText();
if (!inputText.isEmpty()) {
// 使用 QXmlStreamReader 读取输入的 XML 文本
QXmlStreamReader reader(inputText);
QString formattedXml;
int indentLevel = 0;
while (!reader.atEnd() && !reader.hasError()) {
if (reader.isStartElement()) {
formattedXml += getIndent(indentLevel) + "<" + reader.name().toString() + ">\n";
++indentLevel;
} else if (reader.isEndElement()) {
--indentLevel;
formattedXml += getIndent(indentLevel) + "</" + reader.name().toString() + ">\n";
} else if (reader.isCharacters() && !reader.isWhitespace()) {
formattedXml += getIndent(indentLevel) + reader.text().toString() + "\n";
}
reader.readNext();
}
if (reader.hasError()) {
outputTextEdit->setText("XML 解析错误:" + reader.errorString());
} else {
outputTextEdit->setText(formattedXml);
}
} else {
// 如果输入为空,则清空输出区域
outputTextEdit->clear();
}
}
static QString getIndent(int level) {
return QString(level * 4, ' '); // 4空格作为缩进
}
private:
QTextEdit *inputTextEdit;
QPushButton *formatButton;
QTextEdit *outputTextEdit;
};
class NumberBaseConverter : public QWidget {
Q_OBJECT
public:
explicit NumberBaseConverter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
// 横向排列的输入框和选择框
auto *horizontalLayout = new QHBoxLayout();
// 创建输入框并添加到水平布局
inputLineEdit = new QLineEdit(this);
horizontalLayout->addWidget(inputLineEdit);
// 连接输入框的文本变化信号到槽函数
connect(inputLineEdit, &QLineEdit::textChanged, this, &NumberBaseConverter::convertNumber);
// 创建下拉选择框并添加到水平布局
baseComboBox = new QComboBox(this);
baseComboBox->addItem("二进制");
baseComboBox->addItem("八进制");
baseComboBox->addItem("十进制");
baseComboBox->addItem("十六进制");
horizontalLayout->addWidget(baseComboBox);
// 将水平布局添加到垂直布局
layout->addLayout(horizontalLayout);
// 创建四个只读的输出框并添加到垂直布局
binaryOutput = new QLineEdit(this);
binaryOutput->setReadOnly(true);
layout->addWidget(binaryOutput);
octalOutput = new QLineEdit(this);
octalOutput->setReadOnly(true);
layout->addWidget(octalOutput);
decimalOutput = new QLineEdit(this);
decimalOutput->setReadOnly(true);
layout->addWidget(decimalOutput);
hexOutput = new QLineEdit(this);
hexOutput->setReadOnly(true);
layout->addWidget(hexOutput);
// 连接下拉选择框的选择变化信号到槽函数,并进行初始转换
connect(baseComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NumberBaseConverter::convertNumber);
convertNumber(); // 初始转换
setLayout(layout); // 设置整体布局
}
private slots:
void convertNumber() {
QString inputText = inputLineEdit->text();
bool ok;
int base = baseComboBox->currentIndex();
if (!inputText.isEmpty()) {
// 根据所选进制进行转换
if (base == 0) {
int number = inputText.toInt(&ok, 2); // 二进制转十进制
if (ok) {
binaryOutput->setText(inputText);
octalOutput->setText(QString::number(number, 8));
decimalOutput->setText(QString::number(number));
hexOutput->setText(QString::number(number, 16).toUpper());
}
} else if (base == 1) {
// 八进制转换
int number = inputText.toInt(&ok, 8);
if (ok) {
binaryOutput->setText(QString::number(number, 2));
octalOutput->setText(inputText);
decimalOutput->setText(QString::number(number));
hexOutput->setText(QString::number(number, 16).toUpper());
}
} else if (base == 2) {
// 十进制转换
int number = inputText.toInt(&ok, 10);
if (ok) {
binaryOutput->setText(QString::number(number, 2));
octalOutput->setText(QString::number(number, 8));
decimalOutput->setText(inputText);
hexOutput->setText(QString::number(number, 16).toUpper());
}
} else if (base == 3) {
// 十六进制转换
int number = inputText.toInt(&ok, 16);
if (ok) {
binaryOutput->setText(QString::number(number, 2));
octalOutput->setText(QString::number(number, 8));
decimalOutput->setText(QString::number(number));
hexOutput->setText(inputText.toUpper());
}
}
} else {
// 如果输入为空,则清空输出
binaryOutput->clear();
octalOutput->clear();
decimalOutput->clear();
hexOutput->clear();
}
}
private:
QLineEdit *inputLineEdit;
QComboBox *baseComboBox;
QLineEdit *binaryOutput;
QLineEdit *octalOutput;
QLineEdit *decimalOutput;
QLineEdit *hexOutput;
};
class PlaceholderTextEdit : public QWidget {
Q_OBJECT
public:
explicit PlaceholderTextEdit(const QString &placeholderText, QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
placeholderLabel = new QLabel(placeholderText, this);
layout->addWidget(placeholderLabel);
textEdit = new QTextEdit(this);
layout->addWidget(textEdit);
connect(textEdit, &QTextEdit::textChanged, this, &PlaceholderTextEdit::checkPlaceholder);
checkPlaceholder(); // 初始检查
setLayout(layout);
}
QString getText() const {
return textEdit->toPlainText();
}
private slots:
void checkPlaceholder() {
placeholderLabel->setVisible(textEdit->toPlainText().isEmpty());
}
private:
QLabel *placeholderLabel;
QTextEdit *textEdit;
};
class DateTimeTimestampConverter : public QWidget {
Q_OBJECT
public:
explicit DateTimeTimestampConverter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new PlaceholderTextEdit("在此输入日期时间或时间戳", this);
layout->addWidget(inputTextEdit);
convertToTimestampButton = new QPushButton("日期时间转时间戳", this);
connect(convertToTimestampButton, &QPushButton::clicked, this, &DateTimeTimestampConverter::convertToTimestamp);
layout->addWidget(convertToTimestampButton);
convertToDateTimeButton = new QPushButton("时间戳转日期时间", this);
connect(convertToDateTimeButton, &QPushButton::clicked, this, &DateTimeTimestampConverter::convertToDateTime);
layout->addWidget(convertToDateTimeButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
private slots:
void convertToTimestamp() {
QString inputText = inputTextEdit->getText();
QDateTime dateTime = QDateTime::fromString(inputText, "yyyy-MM-dd HH:mm:ss");
if (dateTime.isValid()) {
qint64 timestamp = dateTime.toSecsSinceEpoch();
outputTextEdit->setText(QString::number(timestamp));
} else {
outputTextEdit->setText("无效的日期时间格式!");
}
}
void convertToDateTime() {
QString inputText = inputTextEdit->getText();
bool ok;
qint64 timestamp = inputText.toLongLong(&ok);
if (ok) {
QDateTime dateTime;
dateTime.setSecsSinceEpoch(timestamp);
outputTextEdit->setText("时间戳 " + inputText + " 对应的日期时间是:" + dateTime.toString("yyyy-MM-dd HH:mm:ss"));
} else {
outputTextEdit->setText("无效的时间戳格式!");
}
}
private:
QPushButton *convertToTimestampButton;
QPushButton *convertToDateTimeButton;
QTextEdit *outputTextEdit;
PlaceholderTextEdit *inputTextEdit;
};
class JsonFormatter : public QWidget {
Q_OBJECT
public:
explicit JsonFormatter(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
inputTextEdit = new QTextEdit(this);
layout->addWidget(inputTextEdit);
formatButton = new QPushButton("格式化", this);
connect(formatButton, &QPushButton::clicked, this, &JsonFormatter::formatJson);
layout->addWidget(formatButton);
outputTextEdit = new QTextEdit(this);
outputTextEdit->setReadOnly(true);
layout->addWidget(outputTextEdit);
setLayout(layout);
}
private slots:
void formatJson() {
QString inputText = inputTextEdit->toPlainText();
QJsonParseError error{};
QJsonDocument jsonDoc = QJsonDocument::fromJson(inputText.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
outputTextEdit->setText("JSON 解析错误:" + error.errorString());
return;
}
QJsonObject jsonObj = jsonDoc.object();
QJsonDocument formattedJson(jsonObj);
outputTextEdit->setText(formattedJson.toJson());
}
private:
QTextEdit *inputTextEdit;
QPushButton *formatButton;
QTextEdit *outputTextEdit;
};
class ClipboardManager : public QWidget {
Q_OBJECT
public:
explicit ClipboardManager(QWidget *parent = nullptr) : QWidget(parent) {
auto *layout = new QVBoxLayout(this);
listWidget = new QListWidget(this);
updateList(); // 初始更新列表
auto *clearButton = new QPushButton("清空记录", this);
connect(clearButton, &QPushButton::clicked, this, &ClipboardManager::clearClipboard);
layout->addWidget(listWidget);
layout->addWidget(clearButton);
setLayout(layout);
connect(myApp->clipboard(), &QClipboard::dataChanged, this, &ClipboardManager::updateList);
}
private slots:
void updateList() {
const QClipboard *clipboard = myApp->clipboard();
const QMimeData *mimeData = clipboard->mimeData();
if (mimeData->hasText()) {
const QString clipboardText = mimeData->text();
if (!clipboardText.isEmpty()) {
listWidget->addItem(clipboardText);
}
}
}
void clearClipboard() {
myApp->clipboard()->clear();
listWidget->clear();
}
private:
QListWidget *listWidget;
};
class MyMainWindow : public QWidget {
Q_OBJECT
public:
explicit MyMainWindow(QWidget *parent = nullptr) : QWidget(parent) {
setWindowTitle("天河工具箱");
auto *layout = new QVBoxLayout(this);
auto *clipboardButton = new QPushButton("显示管理粘贴板记录功能");
clipboardButton->setObjectName("clipboardButton");
connect(clipboardButton, &QPushButton::clicked, this, &MyMainWindow::toggleClipboardManager);
clipboardManager = new ClipboardManager(this);
clipboardManager->hide();
layout->addWidget(clipboardManager);
layout->addWidget(clipboardButton);
auto *jsonFormatButton = new QPushButton("显示格式化 JSON 功能");
jsonFormatButton->setObjectName("jsonFormatButton");
connect(jsonFormatButton, &QPushButton::clicked, this, &MyMainWindow::toggleJsonFormatter);
jsonFormatter = new JsonFormatter(this);
jsonFormatter->hide();
layout->addWidget(jsonFormatter);
layout->addWidget(jsonFormatButton);
auto *timestampConverterButton = new QPushButton("显示时间戳转换功能");
timestampConverterButton->setObjectName("timestampConverterButton");
connect(timestampConverterButton, &QPushButton::clicked, this, &MyMainWindow::toggleDateTimeTimestampConverter);
timestampConverter = new DateTimeTimestampConverter(this);
timestampConverter->hide();
layout->addWidget(timestampConverter);
layout->addWidget(timestampConverterButton);
auto *numberBaseConverterButton = new QPushButton("显示进制转换功能");
numberBaseConverterButton->setObjectName("numberBaseConverterButton");
connect(numberBaseConverterButton, &QPushButton::clicked, this, &MyMainWindow::toggleNumberBaseConverter);
numberBaseConverter = new NumberBaseConverter(this);
numberBaseConverter->hide();
layout->addWidget(numberBaseConverter);
layout->addWidget(numberBaseConverterButton);
auto *xmlFormatterButton = new QPushButton("显示XML格式化功能");
xmlFormatterButton->setObjectName("xmlFormatterButton");
connect(xmlFormatterButton, &QPushButton::clicked, this, &MyMainWindow::toggleXmlFormatter);
xmlFormatter = new XmlFormatter(this);
xmlFormatter->hide();
layout->addWidget(xmlFormatter);
layout->addWidget(xmlFormatterButton);
auto *base64ConverterButton = new QPushButton("显示Base64加解密功能");
base64ConverterButton->setObjectName("base64ConverterButton");
connect(base64ConverterButton, &QPushButton::clicked, this, &MyMainWindow::toggleBase64Converter);
base64Converter = new Base64Converter(this);
base64Converter->hide();
layout->addWidget(base64Converter);
layout->addWidget(base64ConverterButton);
setLayout(layout);
}
private slots:
void toggleClipboardManager() {
auto* curButton = findChild<QPushButton*>("clipboardButton");
if (clipboardManager->isHidden()) {
if (curButton) {
curButton->setText("隐藏管理粘贴板记录");
}
clipboardManager->show();
} else {
if (curButton) {
curButton->setText("显示管理粘贴板记录");
}
clipboardManager->hide();
}
}
void toggleJsonFormatter() {
auto* curButton = findChild<QPushButton*>("jsonFormatButton");
if (jsonFormatter->isHidden()) {
if (curButton) {
curButton->setText("隐藏格式化 JSON");
}
jsonFormatter->show();
} else {
if (curButton) {
curButton->setText("显示格式化 JSON");
}
jsonFormatter->hide();
}
}
void toggleDateTimeTimestampConverter() {
auto* curButton = findChild<QPushButton*>("timestampConverterButton");
if (timestampConverter->isHidden()) {
if (curButton) {
curButton->setText("隐藏时间戳转换");
}
timestampConverter->show();
} else {
if (curButton) {
curButton->setText("显示时间戳转换");
}
timestampConverter->hide();
}
}
void toggleNumberBaseConverter() {
auto* curButton = findChild<QPushButton*>("numberBaseConverterButton");
if (numberBaseConverter->isHidden()) {
if (curButton) {
curButton->setText("隐藏进制转换器");
}
numberBaseConverter->show();
} else {
if (curButton) {
curButton->setText("显示进制转换器");
}
numberBaseConverter->hide();
}
}
void toggleXmlFormatter() {
auto* curButton = findChild<QPushButton*>("xmlFormatterButton");
if (xmlFormatter->isHidden()) {
if (curButton) {
curButton->setText("隐藏XML格式化");
}
xmlFormatter->show();
} else {
if (curButton) {
curButton->setText("显示XML格式化");
}
xmlFormatter->hide();
}
}
void toggleBase64Converter() {
auto* curButton = findChild<QPushButton*>("base64ConverterButton");
if (base64Converter->isHidden()) {
if (curButton) {
curButton->setText("隐藏Base64加解密功能");
}
base64Converter->show();
} else {
if (curButton) {
curButton->setText("显示Base64加解密功能");
}
base64Converter->hide();
}
}
private:
ClipboardManager *clipboardManager;
JsonFormatter *jsonFormatter;
DateTimeTimestampConverter *timestampConverter;
NumberBaseConverter *numberBaseConverter;
XmlFormatter *xmlFormatter;
Base64Converter *base64Converter;
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MyMainWindow mainWindow;
mainWindow.show();
return QApplication::exec();
}
#include "main.moc"
想要了解这个小工具是如何发展到现在这个地步的话,就看看往期文章吧~,记得要多跑一跑代码。如果大家有什么想要的功能或者想问的问题的话,就在评论区留言吧。Thanks♪(・ω・)ノ
往期文章一览
C++学习之路(一)什么是C++?如何循序渐进的学习C++?【纯干货】
C++学习之路(二)C++如何实现一个超简单的学生信息管理系统?C++示例和小项目实例
C++学习之路(三)解析讲解超简单学生信息管理系统代码知识点 - 《根据实例学知识》
C++学习之路(四)C++ 实现简单的待办事项列表命令行应用 - 示例代码拆分讲解
C++学习之路(五)C++ 实现简单的文件管理系统命令行应用 - 示例代码拆分讲解
C++学习之路(六)C++ 实现简单的工具箱系统命令行应用 - 示例代码拆分讲解
C++学习之路(七)C++ 实现简单的Qt界面(消息弹框、按钮点击事件监听)- 示例代码拆分讲解
C++学习之路(八)C++ 用Qt5实现一个工具箱(增加一个粘贴板记录管理功能)- 示例代码拆分讲解
C++学习之路(九)C++ 用Qt5实现一个工具箱(增加一个JSON数据格式化功能)- 示例代码拆分讲解
C++学习之路(十)C++ 用Qt5实现一个工具箱(增加一个时间戳转换功能)- 示例代码拆分讲解
C++学习之路(十一)C++ 用Qt5实现一个工具箱(增加一个进制转换器功能)- 示例代码拆分讲解
C++学习之路(十二)C++ 用Qt5实现一个工具箱(增加一个XML文本格式化功能)- 示例代码拆分讲解
好了~ 本文就到这里了,感谢您的阅读,每天还有更多的实例学习文章等着你 🎆。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 🍇。