给定一个初始消息字符串(实际上它的作用类似于格式字符串),并包含随后要填充的占位符。
例如,我们的初始信息是:
“GREETINGS- {year} - {mm-month} - {dd-day} - HELLO WORLD”
哪里有3个占位符,{year},{mm-month},{dd-day}
我想把它翻译成:
“GREETINGS-2016-06-23 - HELLO WORLD”
鉴于我们有一个对象数组如下:
[{
"Key": "{year}",
"Value": "2016"
}, {
"Key": "{mm-month}",
"Value": "06"
}, {
"Key": "{dd-day}",
"Value": "23"
}]
每个对象都有一个与消息中的占位符字符串对应的Key,以及用于替换占位符的Value。
我正在使用R.reduce函数,因为我们有一个值集合(具有键值属性的对象列表,字符串替换器变换器函数(tr),并且初始累加器是原始占位符字符串。
转换函数tr定义为:
let tr =(k,v)=> {return {Key:k,Value:v}}
并且执行文本替换的rp函数定义为:
let rp =(pair,msg)=> {return R.replace(pair.Key,pair.Value,msg); }
因此,期望的效果是迭代列表,用字段值替换字段名称,在每次迭代时,返回部分弹出的字符串,直到最后您有一个完全填充的字符串,没有剩余的占位符。
我使用R.add和R.add模拟了我的解决方案,即:
R.reduce(R.add,0,[1,2,3,4,5]);
对我来说似乎符合相同的模式,除非我错了。
这是R.reduce的调用,它不能按预期工作:
R.reduce(rp,place_holders,pairs)
λ R.reduce(rp, place_holders, pairs);
TypeError: str.replace is not a function
at replace (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/replace.js:25:14)
at Object.f3 [as replace] (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/internal/_curry3.js:35:16)
at XWrap.rp [as f] (repl:2:36)
at XWrap.module.exports.XWrap.@@transducer/step (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/internal/_xwrap.js:10:17)
at _arrayReduce (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/internal/_reduce.js:11:36)
at _reduce (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/internal/_reduce.js:44:14)
at Object.f3 [as reduce] (/Users/devuser/.nvm/versions/node/v10.13.0/lib/node_modules/ramda-repl/node_modules/ramda/src/internal/_curry3.js:35:16)
λ
我在Ramda repl中创建了一个代码片段:ramda-reply code snippet
你非常接近,你只是在你的reducer函数中转换了两个参数。而不是这个:
let rp = (pair, msg) => { return R.replace(pair.Key, pair.Value, msg); }
做这个:
let rp = (msg, pair) => { return R.replace(pair.Key, pair.Value, msg); }
const place_holders = "GREETINGS-{year}-{mm-month}-{dd-day} - HELLO WORLD";
let fields = ['{year}', '{mm-month}', '{dd-day}'];
let vals = ['2016', '06', '23'];
let tr = (k, v) => { return { Key: k, Value: v } }
let pairs = R.zipWith(tr, fields, vals);
let rp = (msg, pair) => { return R.replace(pair.Key, pair.Value, msg);}
console.log(R.reduce(rp, place_holders, pairs))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
正如尼古拉斯塔指出的那样,这个错误是一个简单的换位。我的版本是将命令式代码包装在一个函数中,所以我可能会写这样的东西:
const fillIn = (fields, place_holders, vals) => reduce(
(str, {Key, Val}) => replace(Key, Val, str),
place_holders,
zipWith((Key, Val) => ({Key, Val}), fields, vals)
)
const place_holders = "GREETINGS-{year}-{mm-month}-{dd-day} - HELLO WORLD";
let fields = ['{year}', '{mm-month}', '{dd-day}'];
let vals = ['2016', '06', '23'];
console.log(fillIn(fields, place_holders, vals))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {reduce, replace, zipWith} = R
</script>
如果我想部分应用字段(也许是占位符),我也可能将它包装在curry
中。
更新:您可能还想考虑不同的数据结构。使用两个数组来存储基于共享索引的配对值通常很脆弱。此结构以更健壮的方式保存相同的信息:
{year: '2016', 'mm-month': '06', 'dd-day': '23'}
使用它还可以使用正则表达式更动态地使用占位符:
const fillIn = (placeHolder, context) => placeHolder.replace(
/\{([^}]+)\}/g,
(s, key) => key in context ? context[key] : `{${key}}`
)
const context = {year: '2016', 'mm-month': '06', 'dd-day': '23'}
console.log(fillIn("GREETINGS-{year}-{mm-month}-{dd-day} - HELLO WORLD", context))
console.log(fillIn("GREETINGS-{foobar}-{mm-month}-{dd-day} - HELLO WORLD", context))
这有一个缺点。如果您在字符串中嵌套花括号,则会失败。我实际上会使用更像内置字符串模板的模板,"GREETINGS-${year}-${mm-month}-${dd-day} - HELLO WORLD"
以避免这个问题,并使它们更好地脱颖而出。额外的$
也必须添加到正则表达式,但这很容易:/\$\{([^}]+)\}/g
。
这种技术可能对你没有帮助。如果这些数据结构来自外部系统,那么你就会陷入困境。但是如果你掌控它们,那么可以考虑一下这个你可能已经得到的更灵活,更强大的版本。