2017-01-22 29 views
0

最近、関数型プログラミングに興味を持ち、特にこれをJavaScriptでの私の作業にどのように適用するのかについては非常に興味を持っています。正規表現の使用に関する質問(リンクhere)に答えた後、私は関数型プログラミングのアプローチと比較するためにこれを使用する目的でもう少しアイデアを開発し続けました。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()'関数を試していますが、探しているオブジェクトの配列を得るためのきれいな方法はありません。マッチの配列を取得して、私の現在のソリューションよりも邪魔にならないように見える元の入力でそれぞれを探します)。

ガイダンスをいただければ幸いです。

答えて

1

ラムダの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); 

は明らかに、このコードが異なって構成され、出力のフォーマットからの呼び出し exec正規表現のループを離れて壊す:私は違っそれを考慮かもしれないが、私は、あなたのコードよりも実質的に優れ何も表示されません。さらに微妙には、返された match結果からの情報だけを出力に使用して、正規表現のグローバルな状態に依存しません。それは関数型プログラミングにとって重要だと私に思います。

ラムダのcurryへの呼び出しは純粋なグレービーです。また、あなたが興味を持っている場合、これは、Ramda REPLで提供されています

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

としてこれを書くことができます。

これはあなたのアプローチから大きく変わっていないことに注意してください。私は、ある範囲の正規表現に適用できる著しく異なるアプローチを見ていません。

+0

Scottに感謝します。これはまさに私が探していたものです!私は、正規表現の状態への依存を取り除く方法を見ることができなかったので、質問しました。あなたのソリューションはそれを提供します。私はデータフォーマットの分離が好きで、カレーに関するコメントも役に立ちました。 – rasmeister

0

String.prototype.match()メソッドを使用すると、正規表現を次のようにわずかに変更することができます。

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

あなたは、あなたが以下のようにはるかに高速な方法で同じ仕事をして非正規表現の機能のコードを検討するかもしれないすべての時間を適用する正規表現のこの厳しい条件付き構造を有していますまあ場合には、

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);

あなたは、開始位置と終了位置は、あなたの例とは異なり、それは、彼らが一致したサブ文字列の真の開始位置と終了位置を与えているという理由だけだということに気づくでしょう。 <%%>のインデックスを含むようにコードを簡単に変更することもできます。

+0

このソリューションには、開始位置と終了位置で探しているオブジェクトがありません。私はR.match()で十分に簡単に同じものを得ることができます - 私の現在の正規表現を使用してRamdaの関数ではなく、オブジェクトの配列を使用します。私は理解を広げるために関数型プログラミングの概念を適用した答えを探しています。 – rasmeister

+0

@rasmeister OK私の答えには、正規表現を使わずに探しているオブジェクトを与えるコードが含まれています。 – Redu

関連する問題