查找反范围的功能方法
Functional way of finding inverse ranges
我正在为一个库编写一个模板实用程序,并尝试以一种功能性的方式来完成它(没有可变变量,理想情况下没有中间状态)。 这主要是一个学习练习,我知道已经有图书馆在做这件事。
给定字符串:
"Hello, {{name}}! What are you doing on {{day}}?"`
我已经将模板标签与正则表达式相匹配,它与范围查找功能相结合将 return 标记匹配为 'range' 个对象。
[
{ 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 循环和一些计数器变量来完成,但是你会改变状态。 for
、forEach
和 while
是不可能的。
您将如何在不改变状态的情况下完成这项工作?是否有可能在一次通过中获得所有范围(而不是使用正则表达式然后第二次通过以找到反向范围)?
最终,我将得到一个如下所示的绑定函数列表:
[
text('Hello, '),
lookup('name'),
text('! What are you doing on '),
lookup('day'),
text('?')
]
调用这些将导致一系列查找,这些查找将 return 字符串值和文本函数只是绑定身份函数,它将 return 它们的参数。
假设您的字符串格式正确(平衡的非嵌套 {{
和 }}
),您可以像这样简单地做到这一点:
s.split(/{{|}}/g).map(function (t, i) {
return i % 2 ? lookup(t) : text(t);
});
一件令人惊讶的事情可能是,当您 start/end 带有标签的字符串时,它 starts/ends 带有文本 ('') 的数组。然而,这就是为什么它可以如此简单地完成。
既然你想要 "a list of bound functions",这里有一种方法。
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?"
Would it be possible to get all of the ranges in one pass?
是 - 因为您可以使用带有捕获组的正则表达式来 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);
});
根本不需要范围:-)
我正在为一个库编写一个模板实用程序,并尝试以一种功能性的方式来完成它(没有可变变量,理想情况下没有中间状态)。 这主要是一个学习练习,我知道已经有图书馆在做这件事。
给定字符串:
"Hello, {{name}}! What are you doing on {{day}}?"`
我已经将模板标签与正则表达式相匹配,它与范围查找功能相结合将 return 标记匹配为 'range' 个对象。
[
{ 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 循环和一些计数器变量来完成,但是你会改变状态。 for
、forEach
和 while
是不可能的。
您将如何在不改变状态的情况下完成这项工作?是否有可能在一次通过中获得所有范围(而不是使用正则表达式然后第二次通过以找到反向范围)?
最终,我将得到一个如下所示的绑定函数列表:
[
text('Hello, '),
lookup('name'),
text('! What are you doing on '),
lookup('day'),
text('?')
]
调用这些将导致一系列查找,这些查找将 return 字符串值和文本函数只是绑定身份函数,它将 return 它们的参数。
假设您的字符串格式正确(平衡的非嵌套 {{
和 }}
),您可以像这样简单地做到这一点:
s.split(/{{|}}/g).map(function (t, i) {
return i % 2 ? lookup(t) : text(t);
});
一件令人惊讶的事情可能是,当您 start/end 带有标签的字符串时,它 starts/ends 带有文本 ('') 的数组。然而,这就是为什么它可以如此简单地完成。
既然你想要 "a list of bound functions",这里有一种方法。
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?"
Would it be possible to get all of the ranges in one pass?
是 - 因为您可以使用带有捕获组的正则表达式来 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);
});
根本不需要范围:-)