wingmeng / front-end-quiz

前端小测试答题收集
0 stars 0 forks source link

JS基础测试42:emoji 字符处理 #43

Open wingmeng opened 4 years ago

wingmeng commented 4 years ago

题目:

image

我的回答:

第 1 题

let title = '这是最后一期了,感谢同学们的一路相伴,更要向为47期小测耗费心血的张老师致敬!';

if (title.length > 15) {
  title = title.replace(/^(.{6}).*(.{6})$/, '$1...$2');
}

console.log(title);  // "这是最后一期...张老师致敬!"

第 2 题

let filename = 'weixin_20191221232646.jpg';

if (filename.length > 15) {
  filename = filename.replace(/^(.+)(\.\w+)$/, (_, $1, $2) => {
    let tail = '...' + $1.substr(-1) + $2;
    return $1.substr(0, tail.length - 1) + tail;
  });
}

console.log(filename);  // "weixin_...6.jpg"

第 3 题

思路基本理顺了,但实现上仍然有 bug,待进一步优化 :joy:

function formatTitle(titleStr) {
  // emoji 的 unicode 范围实在是太繁杂了,既有双字节的,还有单字节的
  // 下面的 emoji 正则表达式参考自 lodash@4.16.6
  const regexp_emoji = new RegExp('(' +
    '(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])' +
    '[\ufe0e\ufe0f]?' +
    '(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?' +
    '(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])' +
    '[\ufe0e\ufe0f]?' +
    '(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*' +
  ')', 'g');
  const regexp_symbol = /[,;:……——]/;
  const emojiArr = titleStr.match(regexp_emoji);
  // 将 title 字符串打散成数组,避免双字节 emoji 字符的影响(每个 emoji 算1个字符)
  const titleArr = titleStr.split(regexp_emoji).reduce((arr, s) => {
    if (emojiArr && emojiArr.includes(s)) {
      arr.push(s)
    } else {
      arr = arr.concat(s.split(''))
    }

    return arr;
  }, []);

  if (titleArr.length > 15) {
    const half = Math.floor(titleArr.length / 2);
    let left = titleArr.slice(0, half);
    let right = titleArr.slice(half);
    let leftPoint = 0;
    let rightPoint = 0;

    // 从中心向两端查找第一个 emoji 或中文标点出现的指针位置
    left.some((_, idx, arr) => {
      const index = arr.length - 1 - idx;
      if (emojiArr && emojiArr.includes(arr[index]) || regexp_symbol.test(arr[index])) {
        leftPoint = index + 1;
        return true;
      }
    });
    right.some((item, idx) => {
      if (emojiArr && emojiArr.includes(item) || regexp_symbol.test(item)) {
        rightPoint = idx;
        return true;
      }
    });

    if (leftPoint === 0 && rightPoint === 0) {
      return titleStr.replace(/^(.{6}).*(.{6})$/, '$1...$2');
    }

    let diffValue;

    if (rightPoint > left.length - leftPoint) {
      diffValue = 15 - left.length - 3;  // 差值
      left = left.join('');
      right = right.slice(0, rightPoint).join('') + '...' +
        right.slice(right.length - 1 - rightPoint).join('');
    } else {
      diffValue = 15 - right.length - 3;  // 差值
      left = left.slice(0, left.length - 1 - diffValue).join('') + '...' +
        left.slice(leftPoint).join('');
      right = right.join('');
    }

    return left + right;
  }

  return titleArr.join('');
}