【问题标题】:Convert javascript string length to array of byte[]将javascript字符串长度转换为字节数组[]
【发布时间】:2019-09-11 08:31:42
【问题描述】:

我需要在 javascript 中将字符串的长度转换为长度为 2(16 位有符号整数)的字节数组,相当于 C# Bitconverter.GetBytes(short value)。

示例:295 -> [1,39]。

【问题讨论】:

  • [1,39] 是什么意思?它甚至不是UTF8。我假设你的意思是它是 UTF16BE。即使长度为 1 的 Javascript 字符串也不一定包含 1 个完整的 Unicode 字符。如果它包含一个 unicode 代理,它不是一个字符,而只是一个 16 位代码单元,它不能转换为 UTF16BE(它应该首先与第二个代理配对,以便在 UTF16BE 中转换为 4 个字节和 4 个不同的字节在 UTF8 中)。在 Javascript 中,字符串不限于 UTF16,它们是 16 位代码单元的任意向量,并不总是可以转换为任何 UTF 没有例外或替换。
  • [ value >> 8 & 0xFF, value & 0xFF ]; 返回数字的低 2 个字节。
  • @Thomas 你是对的,但是因为有方法可以做到这一点,Buffer 严格来说是一个字节数组(这是他要求的),最好使用库函数。
  • @EuanSmith 你的回答没有给出我想要的结果。 (295 >> 8 & 0xFF, 295 & 0xFF) -> [1,39] const buf = Buffer.alloc(2); buf.writeUInt16BE(295, 0);控制台.log(buf); 。我认为 Thomas 的答案正是我想要的。

标签: javascript node.js bitconverter


【解决方案1】:

当您使用节点时,Buffer 是您所需要的。查看文档here。例如:

//Make a string of length 295
const st="-foo-".repeat(59);
//Create a byte array of length 2
const buf = Buffer.alloc(2);
//Write the string length as a 16-bit big-endian number into the byte array
buf.writeUInt16BE(st.length, 0);
console.log(buf);
//<Buffer 01 27> which is [1, 39]

请注意,这将为您提供以字符为单位的字符串长度,而不是字符串的字节长度 - 两者可能相同,但不能保证。

【讨论】:

  • 请注意,如果字符串包含单个代理项,如果它包含 2 个字节,结果仍然是无效的 UTF16BE,除非代理项被 BMP 中的其他替换字符替换,例如 U+FFFD 或 ' ?在将其转换为 UTF16BE 中的两个字节之前。所以不要假设 buf.writeUInt16BE() 的结果是有效的 UTF16BE。它只是一个二进制数组,不一定是任何有效 Unicode 形式的文本,但可用于重新创建 javascript 字符串而不会丢失转换。也不要将结果用作 UTF8:它会出现乱码,可能是有效的 UTF8,但无效的 HTML/XML 为空字节。
  • @verdy_p 他最初的问题只是将字符串长度转换为 2 字节表示,而不是字符串本身。所以虽然你是对的,但这不是他问的。我添加了关于 utf8 等的部分,基本上是因为考虑到他的问题,这是他可能正在做的事情,但严格来说,这个问题只是关于从 UInt16 转换为字节数组而不是字符,这就是 Buffer 是什么。
  • 请注意 Buffer.from("\u0B95") 返回一个 3 字节的缓冲区,因为它采用 UTF-8 的默认编码,但 writeUInt16BE() 不会生成 UTF-8 输出。 writeUInt16BE() 的正确缓冲区长度是 Javascript 字符串长度乘以 2(与字符串包含的内容无关)。但结果绝不是有效的 Unicode 编码(不执行 Unicode 验证)。它只是二进制 javascript 字符串内容的另一种二进制表示,使用有序的 8 位字节而不是 16 位代码单元。
  • @verdy_p 提问者没有要求 UTF-8 输出,只是要求一个字节数组。
  • 因此Buffer.from(string) 可能不会分配任何内容,并且如果字符串不是有效的 UTF16(即,如果它包含不成对的代理项)不能转换为 UTF8 并因此没有定义的缓冲区长度,则可能会返回错误.
【解决方案2】:

最后,一个 javascript 字符串内容最终可能会大于 64KB 或更大,因此其转换为字节后的字符串长度可能不适合 16 位整数或 2 个字节。最小代码应首先检查字符串长度(如果st.length&gt;=32768 则抛出错误),然后使用2 字节缓冲区(来自Buffer.alloc(2)),然后将字符串长度与buffer.writeUInt16BE(st.length) 输出到缓冲区。

编写无法处理正确字符串内容的代码通常是个坏主意:包含 32768 个字符或更多字符的文本一点也不例外。但是,如果文本来自具有长度限制的数据库字段,而不是来自 HTML 输入表单字段中的用户输入,则它可能是正确的,这首先需要验证(即使该表单使用 VALID UTF-8,那验证器仍应检查:不要假设“用户”正在使用浏览器,它可能是恶意机器人,试图破坏您的 web 应用程序以获取安全漏洞并获取一些特权或窃取私人数据。

在网络上,在所有处理之前,所有输入字段(包括组合选择器和单选按钮或复选框)都需要对提交的表单数据进行输入验证(有效编码、长度限制、文本格式)(但您可能希望丢弃所有名称不正确的未知字段)。确保您的处理可以处理通过您的网络应用验证器的所有文本长度(包括使用嵌入式网络组件的自包含应用程序,如移动应用程序或桌面应用程序,而不仅仅是网络浏览器)。

恕我直言,使用这样的 16 位假设是很糟糕的,但如果您确保之前已经检查过验证器和实现的长度约束,那么您的问题是有效的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 2021-11-11
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    相关资源
    最近更新 更多