# 字符串转路径数组

const charCodeOfDot = '.'.charCodeAt(0);
const reEscapeChar = /\\(\\)?/g;
const rePropName = RegExp(
  // Match anything that isn't a dot or bracket.
  '[^.[\\]]+' + '|' +
  // Or match property names within brackets.
  '\\[(?:' +
  // Match a non-string expression.
  '([^"\'][^[]*)' + '|' +
  // Or match strings (supports escaping characters).
  '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + ')\\]' + '|' +
  // Or match "" as the space between consecutive dots or empty brackets.
  '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))'
  , 'g');
const stringToPath = memoizeCapped(string => {
  const result = [];
  if (string.charCodeAt(0) === charCodeOfDot) {
    result.push('');
  }
  string.replace(rePropName, (match, expression, quote, subString) => {
    let key = match;
    if (quote) {
      key = subString.replace(reEscapeChar, '$1');
    } else if (expression) {
      key = expression.trim();
    }
    result.push(key);
  });
  return result;
});
  

这一段代码,主要是正则表达式比较复杂,其目的是想将a.b.c字符串转换成['a', 'b', 'c']这样的数组。

主要处理了以下几种情况

# 处理以.开头的字符串

const charCodeOfDot = '.'.charCodeAt(0);
const result = [];
if (string.charCodeAt(0) === charCodeOfDot) {
  result.push('');
}

.开头的字符串,lodash会认为最外层的属性为空字符串。

相当于.a.b.c转换为['', 'a', 'b', 'c']

# 处理常规路径

处理最常规的字符串,例如a.b.c,可以简化成如下代码:

string.replace(rePropName, (match) => {
  let key = match;
  result.push(key);
});

match为匹配成功的字符串,直接push即可。

# 处理中括号取值

在数组取值的情况下,会存在中括号索引的情况,如a[0].b这样的形式,转换为数组是['a', '0', 'b']

在这种情况,可以简化如下的形式:

string.replace(rePropName, (match, expression) => {
  let key = match;
  else if (expression) {
    key = expression.trim();
  }
  result.push(key);
})

在匹配到索引0时,match的结果是[0],但是这里expression的结果是0,因此key0

# 处理带引号的情况

中括号的情况下,可能会存在有引号的情况,如a['0'].b的形式,如果这个string是通过接口返回的,可能还会带上转义字符,如a[\'0\'].b,在这种情况下,quote会存在值,,这是subString在没转义的情况下为0,在有转义字符的情况下为\'0\',因此需要用reEscapeChar正则将转义字符替换掉。

最近更新时间: 2020/9/6 11:30:38