【问题标题】:Functional way of finding inverse ranges查找反向范围的功能方法
【发布时间】:2015-07-26 01:08:49
【问题描述】:

我正在为一个库编写一个模板实用程序,并尝试以一种功能性的方式来完成它(没有可变变量,理想情况下没有中间状态)。 这主要是一个学习练习,我知道那里已经有图书馆这样做了。

给定字符串:

"Hello, {{name}}! What are you doing on {{day}}?"`

我已将模板标签与正则表达式进行匹配,它与范围查找功能相结合会将标记的匹配项作为“范围”对象返回。

[
  { start: 7, end: 14 },
  { start: 39, end: 45 }
]

我想将整个字符串定义为范围,以便我可以将范围编译成函数列表。

[
  { start: 0, end: 6 }
  { start: 7, end: 14, tag: true },
  { start: 15: end: 38 }
  { start: 39, end: 45, tag: true },
  { start: 46, end: 46 }
]

标记它们不是问题,但找到其他范围是问题。这个任务显然可以用一个 for 循环和一些计数器变量来完成,但是你会改变状态。 forforEachwhile 是不可能的。

在不改变状态的情况下如何完成这项工作?是否有可能一次获得所有范围(而不是使用正则表达式然后第二遍来找到反向范围)?

最终,我会得到一个看起来像这样的绑定函数列表:

[
  text('Hello, '),
  lookup('name'),
  text('! What are you doing on '),
  lookup('day'),
  text('?')
]

调用这些将导致一系列查找,这些查找将返回字符串值,而文本函数只是绑定的标识函数,将返回其参数。

【问题讨论】:

  • 我知道这是一个学习练习,但是获取子字符串的位置有什么特别的原因吗?
  • 如果可以,则不然。我的目的是跟踪子字符串索引,以便稍后将它们切出,以便以后构建就地模板函数。
  • replace 方法非常灵活,因为它可以将回调函数作为替换参数,并且使用它你不需要知道索引是什么。
  • 警告!不推荐 "Hello, {{name}}! What are you doing on {{day}}?".match(/\{\{\w+}}|.+?(?=\{\{\w+}}|$)/g)
  • 我在想这样的事情:eval.in/357793(没有建立函数列表的步骤)

标签: javascript regex functional-programming templating


【解决方案1】:

假设您的字符串格式正确(平衡非嵌套{{}}),您可以这样做:

s.split(/{{|}}/g).map(function (t, i) {
    return i % 2 ? lookup(t) : text(t);
});

一个令人惊讶的事情可能是,当您使用标签开始/结束字符串时,它会以 text('') 开始/结束数组。然而,这就是为什么它可以如此简单地完成。

【讨论】:

  • 你的意思是/\{\{|\}\}/g
【解决方案2】:

既然你想要“绑定函数列表”,这里有一种方法。

function lookup() {
  return this.toUpperCase();
}
function text() {
  return this.toString();
}

function parse(input) {
    return input.split(/(?=\{\{)|\}\}/g).map(function (part) {
        var isPlaceholder = part.slice(0, 2) === '{{',
            txt = isPlaceholder ? part.slice(2) : part;
        return (isPlaceholder ? lookup : text).bind(txt);
    });
}

function materialize(parts) {
    return parts.map(function(f) { return f(); }).join("");
}

materialize(parse("Hello, {{name}}! What are you doing on {{day}}?"));
// -> "Hello, NAME! What are you doing on DAY?"

【讨论】:

    【解决方案3】:

    是否有可能一次性获得所有范围?

    是的 - 因为您可以使用带有捕获组的正则表达式来split 您的输入字符串:

    var tag = /(\{\{.+?\}\})/;
    var parts = str.split(tag);
    

    然后你可以直接map那些你的函数:

    var res = parts.map(function(part) {
        return tag.test(part) ? lookup(part.slice(2, -2)) : text(part);
    });
    

    根本不需要范围:-)

    【讨论】:

      猜你喜欢
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-19
      相关资源
      最近更新 更多