字符串截取bug(码元、码点)

本文介绍了计算机中字符编码的过程,特别是UTF-16编码方式。通过UTF-16,每个字符可以由1到2个16位码元表示,码点用于表示字符。文章还讨论了JavaScript中处理字符串码点的方法,如`codePointAt()`和`fromCodePoint()`函数,并提供了一些实用的字符串操作方法,如获取码点长度和按码点截取字符串。
摘要由CSDN通过智能技术生成

计算机存储原理:

a —> 97:将字符转换为数字(ASCII码)的过程称为编码,对于字符编码一般使用的是UTF-16

16位二进制 – 2个字节(1个字节8位二进制)

获取字符串占用的内存空间:字符串length * 2 = 占用的字节数

16位二进制存储范围:2 ** 16 = 65536:0 - 65535 ---> 0000 - ffff(16进制)

当一个16位存不下时,会用两个16位进行存储

两个16位二进制存储范围:2 ** 32 = 4294967296:0 - 4294967295

一个16位存储空间是一个存储的基本单元:Code Unit - 码元

一个文字可能占1个16位,也可能占2个16位:Code Point - 码点

字符串的length — 字符串的码元数量

通过字符串下标 — 获取的也是码元

const str = '🐕❤🏠🚗💴';
str.codePointAt(0);

str.codePointAt(index):获取字符的码点,与65535进行比较,大于65536时表示占用两个码元,小于等于表示占用一个码元。

  • 接收参数为想要获取的目标字符(码点)的开始下标
'🐕'.codePointAt(0);
// 128021
'🐕'.codePointAt(1);
// 56341

String.fromCodePoint(number):将码点转换为字符

  • 接收参数为想要转换的目标码点
String.fromCodePoint(128021);
// 🐕
const str = "🐕❤🏠🚗💴z";

/**
 * 获取字符串的码点长度 -- 实际能看见的字符长度
 */
String.prototype.pointLength = function () {
  let len = 0;
  for (let i = 0; i < this.length; ) {
    const codePoint = this.codePointAt(i);
    i += codePoint > 65535 ? 2 : 1;
    // i += codePoint > 0xffff ? 2 : 1; // 16进制
    len++;
  }
  return len;
};
/**
 * 获取字符串的码点长度 -- 实际能看见的字符长度
 * @param {string} str 目标字符串
 * @returns {number} 字符长度
 */
const pointLength = (str) => {
  let len = 0;
  for (let i = 0; i < str.length; ) {
    const codePoint = str.codePointAt(i);
    i += codePoint > 65535 ? 2 : 1;
    // i += codePoint > 0xffff ? 2 : 1; // 16进制
    len++;
  }
  return len;
};

/**
 * 获取字符串对应下标的字符 -- 码点下标
 * @param {number} index 想要获取的目标字符下标
 * @returns {string} 对应字符
 */
String.prototype.pointAt = function (index) {
  let curIndex = 0; // 码点的下标
  for (let i = 0; i < this.length; ) {
    const codePoint = this.codePointAt(i);

    if (curIndex === index) {
      return String.fromCodePoint(codePoint);
    }
    i += codePoint > 65535 ? 2 : 1;
    curIndex++;
  }
};
/**
 * 获取字符串对应下标的字符 -- 码点下标
 * @param {string} str 目标字符串
 * @param {number} index 获取的码点下标对应的字符
 * @returns {string} 对应字符
 */
const pointAt = (str, index) => {
  let curIndex = 0;
  for (let i = 0; i < str.length; ) {
    const codePoint = str.codePointAt(i);
    if (curIndex === index) {
      return String.fromCodePoint(codePoint);
    }
    i += codePoint > 65535 ? 2 : 1;
    curIndex++;
  }
};

/**
 * 字符串截取,根据码点下标进行截取
 * @param {number} start 开始位置,默认为字符串开始
 * @param {number} end 结束位置,默认为字符串码点长度的长度
 * @returns {string} 截取的目标字符串结果
 */
String.prototype.sliceByPoint = function (start = 0, end = this.pointLength()) {
  let result = "";
  for (let i = start; i < end; i++) {
    result += this.pointAt(i); // i是码点下标
  }
  return result;
};
/**
 * 字符串截取,根据码点下标进行截取
 * @param {string} str 源字符串
 * @param {number} start 开始截取下标,默认为字符串开始
 * @param {number} end 截取结束下标,默认为字符串码点长度
 * @returns {string} 截取的目标字符串结果
 */
const sliceByPoint = (str, start = 0, end = pointLength(str)) => {
  let result = "";
  for (let i = start; i < end; i++) {
    console.log(i, end);
    result += pointAt(str, i);
  }
  return result;
};

// console.log(pointLength(str));
// console.log(str.pointAt(0));
// console.log(str.sliceByPoint(0, 3))
// console.log(str.pointAt(2));
// console.log(pointAt(str, 2));
// console.log(sliceByPoint(str, 0, 3));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值