从 String.prototype.substring 的区间开始

因为使用 String.prototype.substring(start, end) 或者 Array.prototype.slice(start, end) 的时候偶尔会想不起来这些函数的区间代表的是什么。在这里记录一下。

不同函数的差异

这些区间都是 [start, end),即是包括 start,但是不包括 end(当没有传入 end 时,end 视为数组或者字符串等的长度)。但是这个一般只是在 0 >= start >= end 成立,不同函数对参数处理有一些差别。比如 String.prototype.substring 会把负数视为 0,start > end 的时候会做交换,详细情况请看 substring 和 substr 之间的区别

JavaScript 中获取字符串的子串有好几个方法 substr(已废弃)、substringslice,鉴于很多对象都有 slice 方法,且 slice 的参数处理和区间都是一致的,推荐使用 sliceString.prototype.slice 兼容性也没有问题。

slice 的负数区间

String.prototype.slice 可以看到即使是负数,也是满足 [start, end) 的比如:

const str = "The morning is upon us.";
str.slice(-3); // 'us.'
str.slice(-3, -1); // 'us'
str.slice(0, -1); // 'The morning is upon us'
str.slice(4, -1); // 'morning is upon us'

Array.prototype.slice 也是一样。

为什么这样设计

为什么数组应该从 0 开始 提出 a) 2 ≤ i < 13 的形式比 b)1 < i ≤ 12 等其他形式更优美。在 Mesa 语言的实践中 a) 2 ≤ i < 13 也比其他形式更少犯错,更简单。

问问 ChatGPT

ChatGPT 3.5 是这样回答的:

  1. 方便计算长度:通过结束索引减去起始索引,可以直接得到子字符串的长度。
  2. 避免边界混淆:使用左闭右开区间可以避免边界混淆,因为结束索引指示的是下一个字符的位置,而不是最后一个字符的位置。

其他语言

其他语言都是类似的左闭右开区间,比如 Java String:substringGo slice
可以看到大部分现代语言的 slice 使用都是一致的,当然像 Ruby((1..5) => 1, 2, 3, 4, 5 and (1...5) => 1, 2, 3, 4)或者有些方法还提供了额外的参数或者语法可以让你将 end 包括进去。

参考资料

posted @ 2024-04-01 10:28  雷夫·麦  阅读(2)  评论(0编辑  收藏  举报