繁体   English   中英

将Javascript解决方案转换为函数式编程方法

[英]Converting Javascript solution to Functional Programming Approach

最近,我(非常)对函数式编程非常感兴趣,尤其是如何将其应用于我的JavaScript工作。 在回答了有关正则表达式使用的问题之后(我在这里 ,链接),我继续进行更多的构想,以将其与功能性编程方法进行比较。

面临的挑战是编写一个简单的输入解析器,该解析器接受一个正则表达式和一些输入并返回匹配的对象数组(这是更大解决方案的步骤1,但我想从简单开始)。 我可以使用更传统的方法来使用它,但是想对功能编程做同样的事情(我使用的是ramda.js,但只要是JavaScript,就可以使用任何功能编程方法)。

这是工作代码:

var parseInput = function (re, input) {
  var results = [], result;
  while ((result = re.exec(input)) !== null) {
    results.push({
      startPos: result.index,
      endPos: re.lastIndex - 1,
      matchStr: result[1]
    })
  }
  return results;
};

var re = /<%([^%>]+)%>/g;
var input = "A <%test.child%><%more%> name: <%name%> age: <%age%> EOD";

var results = parseInput(re, input);
console.log(results);

我得到的输出看起来像这样:

[ { startPos: 2, endPos: 15, matchStr: 'test.child' },
  { startPos: 16, endPos: 23, matchStr: 'more' },
  { startPos: 31, endPos: 38, matchStr: 'name' },
  { startPos: 45, endPos: 51, matchStr: 'age' } ]

这是我要寻找的结构和结果。

特别是,我一直在尝试使用Ramda和'match()'函数,但是我看不到一种干净的方法来获取想要的对象数组(缺少运行match()来获取数组)的方法。匹配项,然后在原始输入中查找每个匹配项,这似乎比我当前的解决方案麻烦得多)。

指导将不胜感激。

没错,Ramda的match不会为您提供帮助。 专为更简单的用途而设计。 我认为没有什么比您的代码更好的了,尽管我可能会有所不同:

const execAll = R.curry((re, convert, input) => {
  let results = [], result;
  while ((result = re.exec(input))) {
    results.push(convert(result))
  }
  return results;
});

const parseInput = execAll(/<%([^%>]+)%>/g, match => ({
  startPos: match.index,
  endPos: match.index + match[0].length - 1,
  matchStr: match[1]
}));

const input = "A <%test.child%><%more%> name: <%name%> age: <%age%> EOD";

parseInput(input);

显然,此代码的结构不同,将regex exec调用的循环与输出格式分开。 不过,更巧妙的是,它也不依赖于正则表达式的全局状态,仅将返回的match结果中的信息用于其输出。 这对我来说对函数式编程很重要。

Ramda curry招牌是纯肉汁。 您也可以这样写

const execAll = (re, convert) => (input) => { /* ... */ }

如果您有兴趣,可以在Ramda REPL上使用。

请注意,这与您的方法相比并没有太大变化。 我没有看到适用于一系列正则表达式的明显不同的方法。

只需稍微更改您的正则表达式,就可以使用String.prototype.match()方法执行以下操作:

 var str = "A <%test.child%><%more%> name: <%name%> age: <%age%> EOD", rex = /[^<%]+(?=%>)/g, res = str.match(rex); console.log(res); 

好吧,如果您一直使用这种严格的regex条件结构,那么您可以考虑使用非regex功能代码以更快的方式完成相同的工作,如下所示;

 var str = "A <%test.child%><%more%> name: <%name%> age: <%age%> EOD", res = Array.prototype.reduce.call(str, function(r,c,i,s){ c === "%" && s[i-1] === "<" ? (r.select = true, r.push({startPos:i+1, endPos:undefined, matchStr: ""})) : c === ">" && s[i-1] === "%" ? (r.select = false, r[r.length-1].endPos = i-2) : r.select && c !== "%" && (r[r.length-1].matchStr.length ? r[r.length-1].matchStr += c : r[r.length-1].matchStr = c); return r; },[]); console.log(res); 

您会注意到开始位置和结束位置与您的示例有所不同,这仅仅是因为它们给出了匹配子字符串的真实开始位置和结束位置。 您可以轻松地更改代码以包括<%%>的索引。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM