js使用一种方法搞定所有的字符串截取:突破substring的限制
字符串是最基本的数据类型,它有三种最常见的操作:拼接、分隔、截取,今天我们就来说说字符串的截取。
概述
说到字符串的截取,我们可能用到最多的就是substring了,它确实给我们提供了便利,但是用的多了你会发现,其实它也有很多的限制,让你在用的时候总是感觉力不从心。
有没有一种方法,在我截取字符串的时候想怎么弄就怎么弄,而不用去写一堆的辅助代码?
这就是今天我们要介绍的,让你写起代码开心的就像个十八岁的孩子。
准备
我们考虑一下substring的输入和输出,接收两个参数,都是字符串的索引位置,返回这两个索引之间的字符串,可以交换顺序,但是不能传入负数,并且不能按照指定的方向返回。
更不用说它无法传入字符串等等。
我们要实现多参数、多类型的调用,首先想到的就是:重载。
这里我用一个之前我的文章里面的一段代码,用来实现方法重载。
首先,最基本的,我们先用一个数值型参数来截取。
一个数值索引参数
先把我们重载方法引入进来,然后简单实现一下:
import { Overload } from '@/utils/tools/function.js'
const take = Overload()
take.load.n = function(ind: number) {
if(ind < 0) {
return this.substring(this.length + ind)
}
return this.substring(ind)
}
String.prototype.take = take
利用Overload生成一个重载方法,命名为take,表示我们的截取方法。
然后定义它的第一个重载,其中load.n表示重载一个只有一个参数并且为数值型的方法。
最后将它赋值给字符串构造函数的原型上。
如果传入负数,就从后面截取,否则正常截取:
let a = '1234567'
console.log(a.take(4))
console.log(a.take(-3))
看下输出结果:
现在我们继续扩展,可以输入两个数值型参数。
两个数值索引参数
这里就区分了几种情况:都是正数、都是负数、一正一负、前面的大、后面的大。
并且我们希望,可以指定返回字符串的顺序,如果索引1<索引2,那么正常返回,如果索引1>索引2,那么按逆序返回。
这时候我们继续重载一下,然后做一些判断:
take.load.nn = function (ind1: number, ind2: number) {
if(ind1 < 0) {
ind1 = this.length + ind1
if(ind2 < 0) {
ind2 = this.length + ind2
if(ind1 > ind2) {
let s = ''
while(ind1 > ind2) {
s += this.charAt(ind1)
ind1--
}
return s
}else {
this.substring(ind1, ind2)
}
}else{
return this.substring(ind1) + this.substring(0, ind2)
}
}
if(ind2 < 0) {
ind2 = this.length + ind2
let s = ''
while(ind1 > -1) {
s += this.charAt(ind1)
ind1--
}
let last = this.length - 1
while(ind2 < last) {
s += this.charAt(last)
last--
}
return s
}
if(ind1 < ind2) {
return this.substring(ind1, ind2)
}else{
let s = ''
while(ind1 > ind2) {
s += this.charAt(ind1)
ind1--
}
return s
}
}
来测试一下,假设我们有这样一些数据:
let a = '1234567'
console.log(a.take(2,5))
console.log(a.take(5,3))
console.log(a.take(-2,-5))
console.log(a.take(-4,-2))
console.log(a.take(3,-2))
console.log(a.take(2,-3))
console.log(a.take(-4,2))
console.log(a.take(-2,4))
列举出了多种情况,比如第4行,第一个索引是-2,第二个索引是-5,由于索引1>索引2,因此它应该按照逆序返回,而第8行,从倒数第4个数一直截取到正数第3(索引是2)个数。
看下结果:
其中第3、4、6、7都是返回的逆序字符串。
这样我们就能够传入任意的位置,来方便的截取子串,并且能控制返回结果的顺序。
再考虑这样一种场景,我们能不能根据指定的字符串返回结果呢?也就是不关心索引,只要找到某个字符串就返回呢?
我们来尝试一下。
一个字符串参数
同样,我们继续来重载一下:
take.load.s = function(str: string) {
return this.take(this.indexOf(str))
}
这里的load.s表示重载一个只有一个参数并且为字符串型的方法。
它找到这个字符串的位置,并一直截取到最后,看个例子:
let a = 'abcd.docx'
console.log(a.take('.'))
这是一个非常常见的获取文件后缀名的方法,这样我们就可以得到它的值:
那如果它包含多个点呢?没关系,我们再写一个重载,来指定是否从后面截取。
一个字符串,一个布尔值
当第二个参数为false时,从后面开始截取,默认为true:
take.load.sb = function(str: string, head: boolean = true) {
if(head) {
return this.take(this.indexOf(str))
}
return this.take(this.lastIndexOf(str))
}
其中load.sb表示重载一个只有两个参数并且第一个为字符串型,第二个为布尔型的方法。
那么这时即使字符串中包含多个点,也没有关系:
let a = 'abcd.efgh.docx'
console.log(a.take('.'))
console.log(a.take('.', false))
来看下结果:
可以看到非常符合预期。
既然可以这样,那么我们可不可以传入两个字符串,截取它们之间的子串呢?当然可以,你很聪明。
两个字符串参数
跟两个数值型参数一样,我们不但要根据字符串截取子串,并且能够根据它们的位置和传入顺序,来决定返回的子串的顺序:
take.load.ss = function (str1: string, str2: string) {
let ind1
if(!str1){
ind1 = 0
}else{
ind1 = this.indexOf(str1)
}
if(ind1 === -1) {
ind1 = this.length
}
let ind2
if(!str2){
ind2 = this.length
}else{
ind2 = this.indexOf(str2)
}
if(ind2 === -1) {
ind2 = this.length
}
return this.take(ind1, ind2)
}
这样我们就重载了一个可以传入两个字符串的方法,并且给它加了一些判断,第一个参数为空,默认从第一个字符串开始,第二个参数为空,默认截取到最后一个字符。
比如我们看一个它的截取qq号的例子:
let a = '123456@qq.com'
console.log(a.take("", "@"))
这样不用管qq号是多少位的,都能直接提取出来:
我们也可以提取邮箱的后缀:
let a = '123456@163.com'
console.log(a.take("@", ""))
或者邮箱的种类:
let a = '123456@souhu.com'
console.log(a.take("@", "."))
既然到了这一步,那么我们不禁又想,那能不能数字和字符串混合输入呢?聪明如你,一定也想到了,那完全没问题。
一个字符串,一个数值
字符串用来匹配字符,数值用来指定索引。
take.load.sn = function(str: string, ind: number) {
let ind1 = this.indexOf(str)
return this.take(ind1, ind)
}
load.sn表示第一个参数为字符串,第二个参数为数值。
我们同样来考虑数值为正负值的情况:
let a = 'hello world'
console.log(a.take('o', 8))
console.log(a.take('w', -1))
一个数值,一个字符串
不用多说:
take.load.ns = function(ind: number, str: string) {
let ind1 = this.indexOf(str)
return this.take(ind, ind1)
}
来个例子:
let a = 'hello world'
console.log(a.take(2, 'w'))
console.log(a.take(-5, 'o'))
由于o的索引为4,因此-5到4共有9个字符,所以第3行不会到末尾就停止,会继续从头开始找。
相信看到这里,你应该就对开头那段代码的输出结果了然于胸了,可以说整个字符串的截取都是通过take方法来实现的,利用了重载的方式,我们根据不同的参数类型,进行了不同的处理,并且扩展了substring所不能支持的功能,
最后
通过一个函数,我们实现了很多的字符串截取方式,使得我们对于字符串的操作更加灵活,其实这里还能扩展更多的截取方法,比如像Python的切片一样,可以跳步截取,也可以灵活的指定顺序或者逆序,还能扩展出正则匹配的方式进行截取。
不光是字符串截取,字符串的分隔、插入、大小写转换等等都可以以此类推。
只要能提升我们的效率,你想怎么玩那就怎么玩!
转载自:https://juejin.cn/post/7241943960083349563