计算 JavaScript 中以 ISO 8859-7 编码的文件的字节大小

Counting the byte size of a file encoded in ISO 8859-7 in JavaScript

本文关键字:文件 字节 编码 JavaScript 中以 ISO 8859-7 计算      更新时间:2023-09-26

Background

我正在写一种叫做Jolf的深奥语言。它用于可爱的网站代码高尔夫SE。如果您还不知道,很多挑战都是以字节为单位评分的。人们已经制作了许多使用自己的编码或预先存在的编码的语言。

在我的语言解释器上,我有一个字节计数器。如您所料,它会计算代码中的字节数。到目前为止,我一直在使用 UTF-8 en/解码器 ( utf8.js )。我现在使用的是带有希腊字符的ISO 8859-7编码。文本上传实际上也不起作用。我需要计算上传文件中包含的实际字节数。另外,有没有办法读取所述编码文件的内容?

问题

给定从页面上的<input>元素获得的以ISO 8859-7编码的文件,是否有任何方法可以获取该文件中包含的字节数?而且,给定"明文"(即直接放入<textarea>的文本),我如何计算其中的字节,就好像它是在ISO 8859-7中编码的一样?

我尝试过什么

输入元素称为 isogreek 。该文件驻留在<input>元素中。内容是ΦX族,一个希腊字符,一个拉丁字符(每个字符应为一个字节)和一个汉字符,应为多个字节(?

isogreek.files[0].size;      // is 3; should be more.
var reader = new FileReader();
reader.readAsBinaryString(isogreek.files[0]);      // corrupts the string to `ÖX?`
reader.readAsText(isogreek.files[0]);              // �X?
reader.readAsText(isogreek.files[0],"ISO 8859-7"); // �X?

从此评论扩展而来。

正如注释中@pvg提到的,由readAsBinaryString生成的字符串是正确的,但由于两个原因而损坏:

一个。结果以 ISO-8859-1 编码。您可以使用函数来解决此问题:

function convertFrom1to7(text) {
  // charset is the set of chars in the ISO-8859-7 encoding from 0xA0 and up, encoded with this format:
  // - If the character is in the same position as in ISO-8859-1/Unicode, use a "!".
  // - If the character is a Greek char with 720 subtracted from its char code, use a ".".
  // - Otherwise, use 'uXXXX format.
  var charset = "!'u2018'u2019!'u20AC'u20AF!!!!.!!!!'u2015!!!!...!...!.!....................!............................................!";
  var newtext = "", newchar = "";
  for (var i = 0; i < text.length; i++) {
    var char = text[i];
    newchar = char;
    if (char.charCodeAt(0) >= 160) {
      newchar = charset[char.charCodeAt(0) - 160];
      if (newchar === "!") newchar = char;
      if (newchar === ".") newchar = String.fromCharCode(char.charCodeAt(0) + 720);
    }
    newtext += newchar;
  }
  return newtext;
} 

二.中文字符不是 ISO-8859-7 字符集的一部分(因为字符集最多支持 256 个唯一字符,如表所示)。如果要在程序中包含任意 Unicode 字符,则可能需要执行以下两项操作之一:

  1. 以 UTF-8 或 UTF-16 为单位计算该程序的字节数。这可以通过您链接的库轻松完成。但是,如果您希望自动完成此操作,则需要一个函数来检查文本区域的内容是否为有效的 ISO-8859-7 文件,如下所示:
function isValidISO_8859_7(text) {
  var charset = /['u0000-'u00A0'u2018'u2019'u00A3'u20AC'u20AF'u00A6-'u00A9'u037A'u00AB-'u00AD'u2015'u00B0-'u00B3'u0384-'u0386'u00B7'u0388-'u038A'u00BB'u038C'u00BD'u038E-'u03CE]/;
  var valid = true;
  for (var i = 0; i < text.length; i++) {
    valid = valid && charset.test(text[i]);
  }
  return valid;
}
  1. 创建您自己的 ISO-8859-7 自定义变体,该变体使用特定字节(或多个字节)来表示接下来的 2 或 3 个字节属于单个 Unicode 字符。这可以像您喜欢的那样简单或复杂,从一个表示 2 字节字符和一个表示 3 字节的字符到接下来几个设置的 809F 之间的所有内容。下面是一个基本示例,它使用 80 作为 2 字节,81 作为 3 字节(假设文本在 ISO-8859-1 中编码):
function reUnicode(text) {
  var newtext = "";
  for (var i = 0; i < text.length; i++) {
    if (text.charCodeAt(i) === 0x80) {
      newtext += String.fromCharCode((text.charCodeAt(++i) << 8) + text.charCodeAt(++i));
    } else if (text.charCodeAt(i) === 0x81) {
      var charcode = (text.charCodeAt(++i) << 16) + (text.charCodeAt(++i) << 8) + text.charCodeAt(++i) - 65536;
      newtext += String.fromCharCode(0xD800 + (charcode >> 10), 0xDC00 + (charcode & 1023)); // Convert into a UTF-16 surrogate pair
    } else {
      newtext += convertFrom1to7(text[i]);
    }
  }
  return newtext;
}

如果您愿意,我可以更详细地介绍这两种方法。

您作为示例给出的三个字符以 6 个字节a6 ce e6 58 8f 97 (0x58 = X) 解码。另外:JavaScript 与 utf16 一起工作,这导致了一些有趣的事情,比如("abc".length === "ΦX族".length)是真的。

您很可能需要转到完整长度,并通过其代码值检查每个字符的长度。在某些情况下,您可能还需要检查两个字符(utf-32 到 utf-16)。如有必要,还需要放置和检查 BOM(如果您处理未知来源的文件,则始终需要)。

编辑:根据要求添加:

JavaScript 中字符的编码始终采用 utf-16,这是字符的双字节表示形式。这一切都很好,直到他们突然(哈!)发现两个字节对于世界上所有的字母表来说都不够,所以将Unicode的范围扩展到四个字节:utf-32。

好吧,Unicode联盟这样做了,但ECMA委员会没有。

不能说地狱松动了,但在某些情况下它非常接近,其中之一是您的情况,因为您想将单字节编码与多字节编码混合,甚至是不同的编码。

一个字节适合两个字节,

但三个或更多字节不适合两个字节,因此发明了所谓的代理项。这些代理项也是为什么在 JavaScript 中反转字符串不是那么简单的原因。

正如我所说:一大罐蠕虫。