JS:自定义String实例方法(按长度/大写字母分离,去重,排序,逆序,转为HTML/GET/正则,双向截取,从后往前正则匹配,1对1替换=PHP中的strtr(),部分新/旧版的原型方法...)

/**
 * 说明:自定义的字符串原型方法(32)
 * 注意:参数说明开头若已'(xxx)'开头表示默认值
 * 其它:Object.insert()为自定义方法,与Object.assign()类似但不覆盖
 * 其它:如果补充的属性不想被修改或删除,请调用Object.freeze()方法
 */
Object.insert(String.prototype, {
  /**
   * 将字符串按指定长度分割成数组
   * @param {Number+} n (1)分割的字符长度:小于1时无效
   * @param {Number} i (1)开始分割的索引
   * @returns {Array|undefined}
   */
  chunk: function (n, i) {
    n = parseInt(n) || 1
    if (n >= 1) {
      i = parseInt(i) || 0
      const j = this.length
      const r = []
      if (i < 0) i += j
      for (i = Math.max(i, 0); i < j; i += n) r.push(this.substr(i, n))
      return r
    }
  },
  /**
   * 首字母小写
   * @returns {String}
   */
  firstLower: function () {
    return this.length !== 0 ? this[0].toLowerCase() + this.substr(1) : this + ''
  },
  /**
   * 首字母大写
   * @returns {String}
   */
  firstUpper: function () {
    return this.length !== 0 ? this[0].toUpperCase() + this.substr(1) : this + ''
  },
  /**
   * 倒序不区分大小写查询
   * @param {String} s 查询的字符串
   * @param {Number} i (字符长度)最大查询的索引:负数则倒数
   * @returns {Number}
   */
  lastIndexNoCase: function (a, i) {
    return this.slice(0, i).toUpperCase().lastIndexOf(a.toUpperCase())
  },
  /**
   * 正则从后往前查找匹配到的首个文本(长匹配)
   * 注意:原正则中如果有'.'可能会匹配到具有换行符的意外值
   * @param {RegExp} reg 匹配的正则
   * @returns {Array|null} 与*.match()返回的格式完全一致
   */
  lastLongMatch: function (reg) {
    reg = new RegExp(reg, 'g')
    if (reg.test(this)) {
      // 如果查找到,则获取结束位置
      let i = reg.lastIndex
      while (reg.test(this)) i = reg.lastIndex
      // 获取最后的结束位置-1的字符串
      let t = this.substring(--i), tem
      // 重置结束索引并继续查找,直到匹配成功(短匹配)
      reg.lastIndex = 0
      while (!reg.test(t)) t = this[--i] + t
      // 重置正则为起始匹配
      reg = window.eval('/^(' + reg.source + ')/' + reg.flags.replace('g', ''))
      // 因为刚才获取的字符串能被匹配,所以要在前补字符,进行长匹配
      while (reg.test(tem = this[--i] + t)) t = tem
      // 去除g模式后获取匹配数据
      t = t.match(reg)
      // 因为新正则补了括号,所以去除首项
      t.shift()
      // 修正数据
      t.index = ++i
      t.input = this + ''// 去除封装
      return t
    } else return null
  },
  /**
   * 正则从后往前查找匹配到的首个文本(短匹配)
   * 注意:原正则中如果有'.'可能会匹配到具有换行符的意外值
   * @param {RegExp} reg 匹配的正则
   * @returns {Array|null} 与*.match()返回的格式完全一致
   */
  lastShortMatch: function (reg) {
    reg = new RegExp(reg, 'g')
    if (reg.test(str)) {
      // 如果查找到,则获取结束位置
      let i = reg.lastIndex
      while (reg.test(str)) i = reg.lastIndex
      // 获取最后的结束位置-1的字符串
      let tem = str.substring(--i)
      // 重置结束索引并继续查找,直到匹配成功(短匹配)
      reg.lastIndex = 0
      while (!reg.test(tem)) tem = str[--i] + tem
      // 去除g模式后获取匹配数据
      tem = tem.match(window.eval('/' + reg.source + '/' + reg.flags.replace('g', '')))
      // 修正数据
      tem.index = i
      tem.input = str
      return tem
    } else return null
  },
  /**
   * 判断字符串中有无URL的元字符
   * @returns {true|undefined}
   */
  hasUrlChar: function () {
    if (this.match(/\s/)) return
    else {
      const chars = '"#*/:<>?\\|+'
      let i = chars.length
      while (i--) if (this.includes(chars[i])) return
      return true
    }
  },
  /**
   * 模拟同名方法(版本兼容)
   * @param {String} find 匹配的字符串
   * @returns {Boolean}
   */
  includes: function (find) {
    return this.indexOf(find) !== -1
  },
  /**
   * 正序不区分大小写查询
   * @param {String} s 查询的字符串
   * @param {Number} i (0)开始查询的索引:负数则倒数
   * @returns {Number}
   */
  indexNoCase: function (a, i) {
    return this.toUpperCase().indexOf(a.toUpperCase(), i)
  },
  /**
   * 模拟同名方法(版本兼容)
   * 注意:必须使用低版写法
   * @param {Number+} n (0)拼接的次数:若小于0则报错
   * @returns {String}
   */
  repeat: function (n) {
    n = parseInt(n) || 0
    if (n < 0) throw new Error('Invalid count value: ' + n)
    // 利用指数思想拼接字符串
    var t = (this), k = [1], v = [t], i = 2
    for (; i < n; i <<= 1) k.push(i), v.push(t += t)
    n -= i >> 1
    i = k.length
    // 补充剩余字符串
    while (n > 0 && i--) {
      if (n >= k[i]) n -= k[i], t += v[i]
      // 没有也不影响结果,但在一定程度上减少内存溢出情况
      k.pop()
      v.pop()
    }
    return t
  },
  /**
   * 替换对于文件名而言,不允许存在和可能导致异常的字符
   * 常用于:设置文件名
   * @param {String|Function} rep 替换的文本或方法:与*.replace()的第2个参数用法一致
   * @param {Boolean} isOneByOne (假=多个一起替换)是否一对一替换
   * @returns {String}
   */
  replaceUrlChars: function (rep, isOneByOne) {
    return this.replace(isOneByOne ? /["#%'\*\+\/:<>\?\\|]/g : /["#%'\*\+\/:<>\?\\|]+/g, rep)
  },
  /**
   * 字符串逆序
   * @returns {String}
   */
  reverse: function () {
    return this.split('').reverse().join('')
  },
  /**
   * 模拟同名方法(低版兼容)
   * 注意:必须使用低版写法
   * 说明:已测试所有的特殊情况,返回结果均与内置方法一致
   * @param {Number} i 开始截取的索引:负数则倒数
   * @param {Number+} len (截取到最后)截取的长度:小于1均返回空字符串
   * @returns {String}
   */
  slice: function (i, end) {
    var len = str.length
    // 对起始索引强制取整
    if (i = +i || 0) if (i < 0) {
      i += len
      if (i < 0) i = 0
    } else if (i >= len) return ''
    // 对结束索引强制取整
    if (end === undefined) end = len
    else if (end = +end || 0) {
      if (end < 0) {
        end += len
        if (end < 1) return ''
      } else if (end > len) end = len
    } else return ''
    // 截取
    var s = ''
    while (i < end) s += str[i++]
    return s
  },
  /**
   * 字符串排序
   * @returns {String}
   */
  sort: function () {
    return this.split('').sort().join('')
  },
  /**
   * 将字符串按照大写字母分离
   * 说明:若多个大写字符连写,且不是字符串末尾的,则把最后一个字符与后面的文本拼接
   * @returns {Array}
   */
  splitByUpper: function () {
    let a = this.match(/[A-Z]+/g)
    if (!a) return [this.valueOf()]
    let i = 0
      , j = a.length - 1
      , k
      , m = this.indexOf(a[i])
      , n
      , r = m === 0 ? [] : [this.substring(0, m)]
    for (; i < j; i++) {
      k = a[i].length
      n = this.indexOf(a[i + 1], m += k)
      k === 1 ? r.push(this.substring(--m, n)) : r.push(a[i].substring(0, --k), this.substring(--m, n))
      m = n
    }
    k = a[i].length - 1
    // 获取字符串结尾
    n = this.substring(m)
    // 如果最后只有1个大写字符,或者就是字符串末尾,那么直接输出,否则分段输出
    k === 0 || n === a[i] ? r.push(n) : r.push(a[i].substring(0, k), n.substring(k))
    return r
  },
  /**
   * 实现PHP中的strtr()的数组替换方法:逐字或逐键值对替换
   * 注意:若两个参数都为字符串,则只会替换到的最短长度;已被替换的部分不会再次替换
   * @param {String|Object} from 用于替换的字符串或对象
   * @param {String} to (参数1为对象时无效)替换后的字符串
   * @returns {String}
   */
  strtr: function (from, to) {
    if (typeof form === 'object' && form) {
      const key = Object.keys(form)
      const len = key.length
      function r(s, i) {
        return i === len ? s : s.split(key[i]).map(v => r(v, i + 1)).join(form[key[i]])
      }
    } else {
      form += ''
      to += ''
      const len = Math.min(form.length, to.length)
      function r(s, i) {
        return i === len ? s : s.split(form[i]).map(v => r(v, i + 1)).join(to[i])
      }
    }
    return r(this, 0)
  },
  /**
   * 截取所有出现在俩字符串之间的文本
   * @param {RegExp|String} a 前置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {RegExp|String} b 后置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {Number+} i (0)开始查找的索引,负数则倒数
   * @returns {Array} 字符串数组
   */
  subBothAll: function (a, b, i) {
    // 重置字符串;获取模式类型
    let str = this.slice(i), t = '', aa, bb
    const r = []
    if (Object.prototype.toString.call(a) === '[object RegExp]') {
      t = 'r'
      // 如果开启全局模式则去除
      if (a.global) a = window.eval('/' + a.source + '/' + a.flags.replace('g', ''))
    } else {
      t = 's'
      a += ''
    }
    if (Object.prototype.toString.call(b) === '[object RegExp]') {
      t += 'r'
      // 如果开启全局模式则去除
      if (b.global) b = window.eval('/' + b.source + '/' + a.flags.replace('g', ''))
    } else {
      t += 's'
      b += ''
    }
    // 截取数据
    if (t === 'rr') {
      while (true) {
        t = str.match(a)
        if (t) {
          str = str.substring(t.index + t[0].length)
          t = str.match(b)
          if (t) {
            r.push(str.substring(0, t.index))
            str = str.substring(t.index + t[0].length)
          } else break
        } else break
      }
    } else if (t === 'rs') {
      const bl = b.length
      while (true) {
        t = str.match(a)
        if (t) {
          t = str.indexOf(b, i = t.index + t[0].length)
          if (t !== 1) {
            r.push(str.substring(i, t))
            str = str.substring(t + bl)
          } else break
        } else break
      }
    } else if (t === 'sr') {
      i = 0
      const al = a.length
      while (true) {
        t = str.indexOf(a, i)
        if (t !== -1) {
          str = str.substring(t + al)
          t = str.match(b)
          if (t) {
            r.push(str.substring(0, t.index))
            i = t.index + t[0].length
          } else break
        } else break
      }
    } else {
      i = 0
      const al = b.length
      const bl = b.length
      while (true) {
        t = str.indexOf(a, i)
        if (t !== -1) {
          i = str.indexOf(b, t += al)
          if (i !== -1) {
            r.push(str.substring(t, i))
            i += bl
          } else break
        } else break
      }
    }
    return r
  },
  /**
   * 截取首次出现在俩字符串之间的文本√
   * @param {RegExp|String} a 前置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {RegExp|String} b 后置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {Number+} i (0)开始查找的索引,负数则倒数
   * @returns {String|undefined} undefined=未找到
   */
  subBothFirst: function (a, b, i) {
    // 重置字符串/获取模式类型
    let str = this.slice(i), t
    if (Object.prototype.toString.call(a) === '[object RegExp]') {
      t = 'r'
      // 如果开启全局模式则去除
      if (a.global) a = window.eval('/' + a.source + '/' + a.flags.replace('g', ''))
    } else {
      t = 's'
      a += ''
    }
    if (Object.prototype.toString.call(b) === '[object RegExp]') {
      t += 'r'
      // 如果开启全局模式则去除
      if (b.global) b = window.eval('/' + b.source + '/' + b.flags.replace('g', ''))
    } else {
      t += 's'
      b += ''
    }
    // 截取数据
    if (t === 'rr') {
      t = str.match(a)
      if (t) {
        str = str.substring(t.index + t[0].length)
        t = str.match(b)
        if (t) return str.substring(0, t.index)
      }
    } else if (t === 'rs') {
      t = str.match(a)
      if (t) {
        t = str.indexOf(b, i = t.index + t[0].length)
        if (t !== 1) return str.substring(i, t)
      }
    } else if (t === 'sr') {
      t = str.indexOf(a)
      if (t !== -1) {
        str = str.substring(t + a.length)
        t = str.match(b)
        if (t) return str.substring(0, t.index)
      }
    } else {
      t = str.indexOf(a)
      if (t !== -1) {
        b = str.indexOf(b, t += a.length)
        if (b !== -1) return str.substring(t, b)
      }
    }
    return
  },
  /**
   * 截取所有出现在俩字符串之间的文本√
   * @param {RegExp|String} a 前置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {RegExp|String} b 后置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {Number+} i (字符长度)最大查找的索引,负数则倒数
   * @returns {String|undefined} undefined=未找到
   */
  subBothLast: function (a, b, i) {
    // 重置字符串/获取模式类型
    let str = this.slice(i), t
    if (Object.prototype.toString.call(a) === '[object RegExp]') {
      t = 'r'
      // 如果开启全局模式则去除
      if (a.global) a = window.eval('/' + a.source + '/' + a.flags.replace('g', ''))
    } else {
      t = 's'
      a += ''
    }
    if (Object.prototype.toString.call(b) === '[object RegExp]') {
      t += 'r'
      // 如果开启全局模式则去除
      if (b.global) b = window.eval('/' + b.source + '/' + b.flags.replace('g', ''))
    } else {
      t += 's'
      b += ''
    }
    // 截取数据
    if (t === 'rr') {
      t = str.lastLongMatch(b)
      if (t) {
        str = str.substring(0, t.index)
        t = str.lastShortMatch(a)
        if (t) return str.substring(t.index + t[0].length)
      }
    } else if (t === 'rs') {
      t = str.lastIndexOf(b)
      if (t !== -1) {
        str = str.substring(0, t)
        t = str.lastShortMatch(a)
        if (t) return str.substring(t.index + t[0].length)
      }
    } else if (t === 'sr') {
      b = str.lastLongMatch(b)
      if (b) {
        t = str.lastIndexOf(a, b.index)
        if (t !== -1) return str.substring(t + a.length, b.index)
      }
    } else {
      b = str.lastIndexOf(b)
      if (b !== -1) {
        t = str.lastIndexOf(a, b)
        if (t !== -1) return str.substring(t + a.length, b)
      }
    }
  },
  /**
   * 截取出现在俩字符串之间的最长文本√
   * @param {RegExp|String} a 前置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {RegExp|String} b 后置正则(会去除g模式)或字符串:非正则会强制转为字符串
   * @param {Number+} i (0)开始查找的索引,负数则倒数
   * @returns {String}
   */
  subBothLong: function (a, b, i) {
    // 重置字符串/获取模式类型
    let str = this.slice(i), t
    if (Object.prototype.toString.call(a) === '[object RegExp]') {
      t = 'r'
      // 如果开启全局模式则去除
      if (a.global) a = window.eval('/' + a.source + '/' + a.flags.replace('g', ''))
    } else {
      t = 's'
      a += ''
    }
    if (Object.prototype.toString.call(b) === '[object RegExp]') {
      t += 'r'
      // 如果开启全局模式则去除
      if (b.global) b = window.eval('/' + b.source + '/' + b.flags.replace('g', ''))
    } else {
      t += 's'
      b += ''
    }
    // 截取数据
    if (t === 'rr') {
      t = str.match(a)
      if (t) {
        str = str.substring(t.index + t[0].length)
        if (t = str.lastLongMatch(b)) return str.substring(0, t.index)
      }
    } else if (t === 'rs') {
      t = str.lastIndexOf(b)
      if (t !== -1) {
        str = str.substring(0, t)
        t = str.match(a)
        if (t) return str.substring(t.index + t[0].length)
      }
    } else if (t === 'sr') {
      t = str.indexOf(a)
      if (t !== -1) {
        str = str.substring(t + a.length)
        if (t = str.lastLongMatch(b)) return str.substring(0, t.index)
      }
    } else {
      t = str.indexOf(a)
      if (t !== -1) {
        str = str.substring(t + a.length)
        t = str.lastIndexOf(b)
        if (t !== -1) return str.substring(0, t)
      }
    }
  },
  /**
   * 截取字符串首次出现之后的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} i (0)结束截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subFirstAfter: function (match, i) {
    // 重置字符串;获取模式类型
    const str = this.slice(0, i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      i = str.match(match)
      return i ? str.substring(i.index + i[0].length) : null
    } else {
      i = str.indexOf(match += '')
      return i === -1 ? null : str.substring(i + match.length)
    }
  },
  /**
   * 截取字符串首次出现之前的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} i (0)开始截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subFirstBefore: function (match, i) {
    // 重置字符串;获取模式类型
    const str = this.slice(i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      i = str.match(match)
      return i ? str.substring(0, i.index) : null
    } else {
      i = str.indexOf(match + '')
      return i === -1 ? null : str.substring(0, i)
    }
  },
  /**
   * 截取字符串出现第n次之后的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} n (1)查找第几个匹配到的文本:非数字或负数均为1
   * @param {Number+} i (0)开始截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subIndexAfter: function (match, n, i) {
    // 对n强制取整
    n = +n || parseFloat(n) || 1
    n = Math.min(Math.max(n, 1), this.length)
    // 重置字符串;获取模式类型
    let str = this.slice(i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      // 匹配到指定次数
      for (; n !== 0 && (i = str.match(match)); n--) str = str.substring(i.index + i[0].length)
      return i ? str : null
    } else {
      match += ''
      const ml = match.length
      // 匹配到指定次数
      i = str.indexOf(match)
      for (n--; n > 0 && i !== -1; n--) i = str.indexOf(match, i + ml)
      return i === -1 ? null : str.substring(i + ml)
    }
  },
  /**
   * 截取字符串出现第n次之前的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} n (1)查找第几个匹配到的文本:非数字或负数均为1
   * @param {Number+} i (0)开始截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subIndexBefore: function (match, n, i) {
    // 对n强制取整
    n = +n || parseFloat(n) || 1
    n = Math.min(Math.max(n, 1), this.length)
    // 重置字符串;获取模式类型
    let str = this.slice(i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      // 匹配到指定次数
      let tem = str
      for (; n !== 0 && (i = tem.match(match)); n--) tem = tem.substring(i.index + i[0].length)
      return i ? str.substring(0, str.length - tem.length - i[0].length) : null
    } else {
      match += ''
      const ml = match.length
      // 匹配到指定次数
      i = str.indexOf(match)
      for (n--; n > 0 && i !== -1; n--) i = str.indexOf(match, i + ml)
      return i === -1 ? null : str.substring(0, i)
    }
  },
  /**
   * 截取字符串最后出现之后的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} i (字符长度)结束截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subLastAfter: function (match, i) {
    // 重置字符串;获取模式类型
    const str = this.slice(0, i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      i = str.lastShortMatch(match)
      return i ? str.substring(i.index + i[0].length) : null
    } else {
      i = str.lastIndexOf(match += '')
      return i === -1 ? null : str.substring(i + match.length)
    }
  },
  /**
   * 截取字符串最后出现之前的文本√
   * @param {RegExp|String} match 查找的正则(会去除g模式)或文本:非正则会强制转为字符串
   * @param {Number+} i (字符长度)结束截取的索引:负数则倒数
   * @returns {String|null} null=未找到
   */
  subLastBefore: function (match, i) {
    // 重置字符串;获取模式类型
    const str = this.slice(0, i)
    if (Object.prototype.toString.call(match) === '[object RegExp]') {
      // 如果开启全局模式则去除
      if (match.global) match = window.eval('/' + match.source + '/' + match.flags.replace('g', ''))
      i = str.lastLongMatch(match)
      return i ? str.substring(0, i.index) : null
    } else {
      i = str.lastIndexOf(match + '')
      return i === -1 ? null : str.substring(0, i)
    }
  },
  /**
   * 模拟同名方法(防止失效)
   * 注意:必须使用低版写法
   * 说明:已测试所有的特殊情况,返回结果均与内置方法一致
   * @param {Number} i 开始截取的索引:负数则倒数
   * @param {Number+} len (截取到最后)截取的长度:小于1均返回空字符串
   * @returns {String}
   */
  substr: function (i, len) {
    const max = str.length
    // 对起始索引强制取整
    if (i = +i || 0) if (i < 0) {
      i += max
      if (i < 0) i = 0
    } else if (i >= max) return ''
    // 对结束索引强制取整
    if (len === undefined) len = max
    else if (len = +len) {
      if (len < 1) return ''
      else if (len < max) len = Math.min(len + i, max)
      else len = max
    } else return ''
    // 截取
    let s = ''
    while (i < len) s += str[i++]
    return s
  },
  /**
   * 模拟同名方法(低版本兼容)
   * 注意:必须使用低版写法
   * 说明:已测试所有的特殊情况,返回结果均与内置方法一致
   * @param {Number} i 开始截取的索引:小于1均为0
   * @param {Number+} end (undefined=截取到最后)最后截取的索引
   * @returns {String}
   */
  substring: function (i, end) {
    let max = str.length
    // 对起始索引强制取整
    if (i = +i || 0) {
      if (i < 0) i = 0
      else if (i > max) i = max
    }
    // 对结束索引强制取整
    if (end === undefined) end = max
    else {
      end = +end || 0
      if (end < 0) end = 0
      else if (end > max) end = max
    }
    // 截取
    let s = ''
    if (i < end) while (i < end) s += str[i++]
    else while (end < i) s += str[end++]
    return s
  },
  /**
   * 把HTML文本解析为正常文本
   * @param {String} lineBreak ('\r\n')换行符:非'\r'或'\n'均为默认值
   * @returns {String}
   */
  toHTML: function (lineBreak) {
    // 用于转化HTML和字符实体
    const e = document.createElement('span')
    // 转化HTML、字符实体、换行符
    return this.replace(/&(#\d|\w)+;/g, v => {
      e.innerHTML = v
      return e.textContent
    }).replace(/\n|\r/g, lineBreak === '\r' || lineBreak === '\n' ? lineBreak : '\r\n')
  },
  /**
   * 把字符串按照GET请求解析,并支持多选:多选格式=[{k:二维键名,v:数据},...]
   * 说明:需兼容低版写法
   * @param {String} prefix (undefined='')每个键名要拼接的前缀:防止与原型冲突
   * @returns {Object}
   */
  toGET: function (prefix) {
    // 把参数强制转为字符串
    prefix = prefix === undefined ? '' : prefix + ''
    var r = {}
      // 获取请求数据,但因键名中可能存在'&',所以此时还不能转码
      , a = location.search.substring(1).split('&')
      , i = 0, j = a.length, k, v
    for (; i < j; i++) {
      k = a[i].indexOf('=')
      // 转码
      if (k === -1) {
        v = ''
        k = decodeURIComponent(a[i])
      } else {
        v = decodeURIComponent(a[i].substring(k + 1))
        k = decodeURIComponent(a[i].substring(0, k))
      }
      // 多选判断
      var k1 = k.indexOf('['), k2 = k1 === -1 ? -1 : k.indexOf(']', k1 + 1)
      if (k2 === -1) r[prefix + k] = v
      else {// 是多选时
        k = prefix + k.substring(0, k1)// 1维键名
        // 添加到对象数组中
        if (typeof r[k] !== 'object') r[k] = []
        r[k].push({ k: k.substring(k1 + 1, k2), v: v })
      }
    }
    return r
  },
  /**
   * 把字符串转为正则:主要处理正则的元字符
   * @param {String} model (无模式)转化后正则的模式:是字符串时会强制转为小写字符串
   * @param {Boolean|String} toMetaChars (假=不转化)Boolean=是否转化所有字符;String=要转化的元字符(非字符串会被强制转化)
   * @returns {RegExp|false} false=转化失败
   */
  toRegExp: function (model, toMetaChars) {
    let str = this
    // 转化正则模式
    model = typeof model === 'string' ? model.toLowerCase() : ''
    // 如果要转化元字符
    if (toMetaChars) {
      const metaChars = '\\$()*+-./?[]^{}' // 必须以"\\"开头,且无重复字符
      const ml = metaChars.length
      let i = 0
      // 为true则全部转义,否则仅转义参数中存在的
      if (toMetaChars === true)
        for (; i < ml; i++) str = str.split(metaChars[i]).join('\\' + metaChars[i])
      else
        for (toMetaChars += ''; i < ml; i++) if (toMetaChars.includes(metaChars[i])) str = str.split(metaChars[i]).join('\\' + metaChars[i])
    }
    try {
      return new RegExp(str, model)
    } catch (e) {
      throw new Error(e)
    }
  },
  /**
   * 字符串去重
   * @returns {String}
   */
  unique: function () {
    let a = this, r = ''
    while (a) {
      r += a[0]
      a = a.split(a[0]).join('')
    }
    return r
  },
})
Object.freeze(String.prototype)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值