Nodejs将字符串转换为UTF-8

72

从我的数据库中获取到以下字符串:

Johan Öbert

它应该表达的是:

Johan Öbert

我已经尝试将它转换成 utf-8 格式:

nameString.toString("utf8");

但问题仍然存在。

有任何想法吗?


4
让你的数据库返回UTF-8格式? - robertklep
8个回答

86

我建议使用Buffer对象:

var someEncodedString = Buffer.from('someString', 'utf-8').toString();

这样做可以避免其他答案所需的任何不必要的依赖关系,因为 Buffer 已经包含在 node.js 中,并已在全局范围内定义。


3
在尝试使用答案中建议的utf8软件包后仍然无法解决问题,但是只用了您的这一行代码就可以轻松解决。谢谢! - ArendE
4
这是否是从 UTF-8 转换而不是转换为 UTF-8? - romor
这个应该是 Buffer.from('someString', 'your-encoding').toString('utf-8'); 吗? - E.Belekov
这是对我有效的方法:Buffer.from(fileName, 'ascii').toString('utf-8') - undefined

57

使用npm中的 utf8 模块进行字符串编码/解码。

安装:

npm install utf8

在浏览器中:
<script src="utf8.js"></script>

在Node.js中:

const utf8 = require('utf8');

API:

编码:

utf8.encode(string)

将任何给定的 JavaScript 字符串 (string) 编码为 UTF-8,并返回该字符串的 UTF-8 编码版本。如果输入字符串包含非标量值,即单独代理项,则会引发错误。(如果您还需要能够编码非标量值,请使用 WTF-8.)

// U+00A9 COPYRIGHT SIGN; see http://codepoints.net/U+00A9
utf8.encode('\xA9');
//'\xC2\xA9'
// U+10001 LINEAR B SYLLABLE B038 E; see http://codepoints.net/U+10001
utf8.encode('\uD800\uDC01');
//'\xF0\x90\x80\x81'

解码:

utf8.decode(byteString)

将任何给定的UTF-8编码字符串(byteString)解码为UTF-8,并返回字符串的UTF-8解码版本。如果检测到UTF-8格式错误,则会抛出错误。(如果您需要能够解码编码的非标量值,请使用WTF-8。)

utf8.decode('\xC2\xA9');
//'\xA9'

utf8.decode('\xF0\x90\x80\x81');
//'\uD800\uDC01'
// → U+10001 LINEAR B SYLLABLE B038 E

资源


2
该模块未能进行转换,输出仍然不正确。 - Alosyius
1
我原以为我需要进行编码,但实际上在我的情况下需要使用utf8.decode。这是来自一个使用latin1而应该使用utf8的mysql数据库。 - RobKohr
4
为什么不使用 Buffer.fromStringDecoder - Константин Ван

21

我遇到了同样的问题,当我通过fs.readFile()加载文本文件时,我尝试将编码设置为UTF8,但没有起作用。我的解决方案是:

myString = JSON.parse( JSON.stringify( myString ) )

在此之后,Ö将被真正解释为Ö。


2
这对我有效。其他一切都没有。UTF8模块会崩溃,并显示一个关于字符串类型缺少某种扩展的错误。iConv模块无法安装,因为它要求在安装期间进行编译...简直是些愚蠢的东西。 - Thraka

7
当你想要更改编码时,总是需要从一个编码格式转换到另一种。因此,你可能会从 Mac Roman 转换为 UTF-8 或从 ASCII 转换为 UTF-8
了解所需的输出编码和当前源编码同样重要。例如,如果你有 Mac Roman,并且将其从 UTF-16 解码为 UTF-8,那么你将只会得到乱码。
如果你想要了解更多关于编码的知识,这篇文章会详细介绍:

每个程序员在使用文本时都必须绝对明白编码和字符集的知识

使用 node-iconviconv-lite 的 npm 包 encoding 应该可以让你轻松指定你想要的源和输出编码:
var resultBuffer = encoding.convert(nameString, 'ASCII', 'UTF-8');

如果您的字符串是ASCII或特别是7位US-ASCII,则该字符串已经是UTF-8了。根本不需要进行转换。但是,仍然需要将“Mac Roman”转换为UTF-8。 - lwchkg

2

你应该在数据库连接中设置字符集,而不是在nodejs内部进行调整:

SET NAMES 'utf8';

(适用于MySQL和PostgreSQL)

请记住您需要为每个连接运行此操作。如果您正在使用连接池,请使用事件处理程序执行此操作,例如:

mysqlPool.on('connection', function (connection) {
  connection.query("SET NAMES 'utf8'")
});

https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-client-configuration https://www.postgresql.org/docs/current/multibyte.html#id-1.6.10.5.7 https://www.npmjs.com/package/mysql#connection


2

TextEncoder(自Node.js v11起可用),以及Node的buffer模块都可以实现此功能。

TextEncoder

const encoder = new TextEncoder();
const bytes = encoder.encode('Johan Öbert');
const decoder = new TextDecoder('utf-8');
console.log(decoder.decode(bytes));

Node.js Buffer

就 Node 的 buffer 模块而言,UTF-8 是默认的 .toString 编码。

在转换 Buffers 和字符串之间时,可以指定字符编码。如果没有指定字符编码,默认将使用 UTF-8。 source

Buffer.from('Johan Öbert').toString();

注意:这两个都不能将字符串“Johan Öbert”更改为“Johan Öbert”。

0
这里的其他答案要么有些不正确,要么有些误导性。这可能会让那些不了解实际情况细节的人感到困惑。
在Node.js中,如果你有一个字符串,它已经是内部的UTF-8编码了。从逻辑上讲,Node.js将字符串处理为Unicode字符串。无论它是UTF-8、UTF-16、UTF-32还是其他编码方式,这些细节都不重要。将一个字符串“转换”为UTF-8是没有意义的。
如果你在Node.js中有一个Unicode字符串,并且想要得到组成该字符串的字节以特定编码方式表示,你可以使用以下方法:
const string = "Johan Öbert";
const utf8_buffer = Buffer.from(string, "utf8");
const utf16_buffer = Buffer.from(string, "utf16le");

从这个例子中可以看出,string没有任何编码。但是,你可以使用Buffer.from轻松计算出用于构成特定编码的字节。
如你所见here,支持以下编码:utf8/utf-8utf16le/utf-16lelatin1base64base64urlhex,以及asciibinarylatin1的别名),ucs2/ucs-2utf16le的别名)的旧版编码。
关于旧编码:`ascii` 是误导性的,它在写入时的行为类似于 `latin1`,而在读取时用于清理垃圾数据;`binary` 与二进制数据没有更多关联,它的行为也类似于 `latin1`;`ucs2`/`ucs-2` 不准确,并且行为类似于 `utf16le`,而不是真正的 UCS-2。
在某些特殊情况下,你可能需要使用 `ascii`,但其他旧编码没有任何价值,因为它们只是非旧编码的别名。使用非旧编码可以使你的代码更清晰,应该优先考虑使用它们。
如果你有一个看起来编码错误的字符串,有几件事情需要记住:
1. 你必须知道被错误解码的数据的原始编码。 2. 并非所有错误编码都可以恢复。 3. 许多默认的旧编码(如 windows-1252)是不可恢复的。 4. 你几乎肯定有一个上游数据问题;不要从尝试使用 Node.js 在不同编码之间操作缓冲区开始。
首先,如果你的数据库中存在乱码解码问题,你需要在数据库中进行修复。这可能是在创建表结构时设置表或列的编码标志。这可能是应用程序写入数据库时的连接设置。这可能是你的Node.js应用程序从数据库中读取时的连接设置。从这里开始,确定出现问题的地方。确保表将数据存储在有用的格式中。确保所有连接都使用/期望相同的编码。
其次,如果数据库连接/表存在不匹配,可能会导致数据损坏。一般规则是始终没有例外)在任何支持UTF-8的情况下始终使用UTF-8。在错误使用连接编码或表/列编码时,往往会导致数据丢失。即使没有数据丢失,你仍然可能需要重新对数据库中的所有数据进行重新编码,以便有效使用。
我所知道的唯一不支持UTF-8的常见情况是MS SQL Server中的TEXT列和MS SQL Server 2019之前的CHAR/VARCHAR列。我认为Oracle也有一些限制,只支持整个数据库的单一编码,适用于所有连接。
第三,如果你需要修复垃圾数据(即问题不是读取数据库时使用的连接编码),你可以使用两种策略之一来修复不正确的数据。
如果你有像base64这样的Buffer支持,那就很幸运了。这很简单:
// actual question is not supported by Buffer
const corrected = Buffer.from("Sm9oYW4gw5ZiZXJ0", "base64").toString();

如果你的坏数据是使用Buffer不支持的编码方式,但是是TextDecoder支持的编码方式之一,你可以像下面这样做:
// start with badly encoded string
const string = "Johan Öbert";
// get UTF-8 bytes that make up this string
const bytes = Buffer.from(string, "utf8");
// re-decode the bytes using the correct decoder
// NOTE: actual bad data is NOT windows-1252 (q.v. #1 above)
const corrected = new TextDecoder("windows-1252").decode(bytes);

-2
只需添加此<?xml version="1.0" encoding="UTF-8"?>,即可进行编码。例如,在添加此代码后,任何字符都可以用于制作RSS。
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
    >....

同时添加到您的父布局或主要的app.html中 <meta charset="utf-8" />

<!DOCTYPE html>
<html lang="en" class="overflowhere">
    <head>
        <meta charset="utf-8" />

    </head>
</html>

1
OP要求使用node.js,但这个解决方案只能在浏览器上使用。 - sametcodes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接