簡體   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