以类似markdown的标记语言

时间:2018-03-28 10:21:48

标签: javascript parsing

我有一个类型的字符串:

'??__HELLO__?? WORLD ##SAMPLE --MAIN--##'

我需要解析它并获取包含以下内容的数组:

[{ marker: '??', value: { marker: '__', value: 'HELLO' }, ' WORLD ', { marker: '##', value: ['SAMPLE ' , { marker: '--', value: 'MAIN' }]]

所以我有这个arkers:

this.markers = {
        b: '??',
        i: '##',
        u: '__',
        s: '--',
    };

我有一个生成堆栈的函数:

parse(string) {
    this.string = string;
    this.stack = [];

    for (let i = 0; i < string.length; i++) {
        for (let marker of Object.values(this.markers)) {
            if (string[i] + string[i + 1] === marker) {
                this.stack.push({ marker: marker, index: i });
                this.stack.push('');
                i++;
                break;
            } else if (marker === Object.values(this.markers)[Object.values(this.markers).length - 1]) {
                this.stack[this.stack.length - 1] = this.stack[this.stack.length - 1].concat(string[i]);
                break;
            }
        }
    }

    for (let i = 0; i < this.stack.length; i++) {
        if (this.stack[i] === '') {
            this.stack.splice(i, 1);
            i--;
        }
    }

    console.log(this.stack);
    return this.parseRecursively(this.stack[0]);
}

在我的示例中,堆栈将包含:

[ { marker: '??', index: 0 },
{ marker: '__', index: 2 },
'HELLO',
{ marker: '__', index: 9 },
{ marker: '??', index: 11 },
' WORLD ',
{ marker: '##', index: 20 },
'SAMPLE ',
{ marker: '--', index: 26 },
'MAIN',
{ marker: '--', index: 31 },
{ marker: '##', index: 33 } ]

此函数调用另一个递归生成输出数组的函数:

parseRecursively(element) {
    if (this.stack.length === 0) {
        return;
    }

    let parsed = [];

    for (let i = this.stack.indexOf(element); i < this.stack.length; i++) {
        if (typeof this.stack[i] === 'object') {
            if (this.stack[i].marker === this.stack[this.stack.indexOf(this.stack[i]) + 1].marker) {
                let popped = this.stack.splice(this.stack.indexOf(this.stack[i]) + 1, 1)[0];
                let popped2 = this.stack.splice(this.stack.indexOf(this.stack[i]), 1)[0];

                return { marker: popped.marker, value: this.string.substring(popped2.index + 2, popped.index) };
            } else {
                parsed.push({ marker: this.stack[i].marker, value: this.parseRecursively(this.stack[this.stack.indexOf(this.stack[i]) + 1]) });
                i = -1;
            }
        } else {
            parsed.push(this.stack.splice(this.stack.indexOf(this.stack[i]), 1)[0]);
            i -= 2;
        }
    }

我尝试了上述函数的许多实现,但它仍然无法解析字符串。

那么我该如何重写这个功能呢?

谢谢!

P.S。只有普通的JavaScript,仅此而且我认为使用正则表达式将有助于更轻松地解决它,这里是我的正则表达式:

this.regex = /(\?{2}|#{2}|\-{2}|_{2})(.+?)(\1)/g;

1 个答案:

答案 0 :(得分:1)

好的,经过一番思考,这是我对你的问题的看法:

function parse(str, markers = ['??', '__', '##', '--']) {
  // Escape the markers (mostly useless...)
  const e = markers.map(m => m.replace(/./g, '\\$&'))

  // Create regexs to match each individual marker.
  const groups = e.map(m => new RegExp('(' + m + ')(.*?)' + m));

  // Create the regex to match any group.
  const regex = new RegExp('(' + e.map(m => m + '.*?' + m).join('|') + ')');
  const output = [];

  // 'Match' the groups markers.
  str = str.split(regex).filter(_ => _);

  // Iterate over each of the split markers. e.g.
  // From: '??__HELLO__?? WORLD ##SAMPLE --MAIN--##'
  //   To: ['??__HELLO__??', ' WORLD ', '##SAMPLE --MAIN--##']
  return str.map(match => {
    // Find the marker if it is a marker.
    marker = groups.find(m => m.test(match));

    // If it's not a marker return the value.
    if (!marker) {
      return match.trim();
    }

    // It is a marker so make the marker object.
    match = match.match(marker);
    return {
      marker: match[1],
      // Do the recursion.
      value: parse(match[2], markers)
    }
  })
}

// Usage example:
console.log(
  parse('??__HELLO__?? WORLD ##SAMPLE --MAIN--##')
);
.as-console-wrapper {min-height: 100%;}

此代码中使用的各个正则表达式以以下样式构建:

  1. 逃避每一个角色; ??变为\?\?
  2. 标记是孤立的; \?\?变为(\?\?)
  3. 使用以下正则表达式匹配内容; (.*?)
  4. 然后内容被标记包围; (\?\?)(.*?)\?\?
  5. 这意味着默认的正则表达式数组如下所示:

    [
      /(\?\?)(.*?)\?\?/,
      /(\_\_)(.*?)\_\_/,
      /(\#\#)(.*?)\#\#/,
      /(\-\-)(.*?)\-\-/
    ]
    

    匹配任何标记正则表达式将如下所示:

    /\?\?.*?\?\?|\_\_.*?\_\_|\#\#.*?\#\#|\-\-.*?\-\-/
    

    实际上是相同的正则表达式,只是没有匹配的组。