1

わかりました、最初に、TL;DR で申し訳ありません...

第二に、私が達成したいことについてのいくつかの文脈。

特定のファイルを処理し、定義された一連のルールに基づいて新しいファイルを生成するスクリプトがあります。ファイルの各行には値があり、スクリプトは値を評価し、その値と一般的なルールに基づいて他の値を生成します。生成されたファイルには、元の値と生成された値が csv 形式で含まれています。

例えば:

入力ファイル:

row1value
row2value

出力ファイル:

"row1value","generatedValue1","generatedValue2","generatedValue3"
"row2value","generatedValue1","generatedValue2","generatedValue3"

たとえば、ソース ファイルの各行にコロンで区切られた値があり、目的は値をコロンで分割し、各サブ値を列に入れることだとします。これは、「前」と「後」がどのように見えるかです。

入力ファイル:

a:b:c
some:random:value

出力ファイル:

"a:b:c","a","b","c"
"some:random:value","some","random","value"

行を生成するには、次のようにします。

function generateRow ($key) {
  // $key is the value for the current row being processed from the source file
  // $row is the array that will contain the columns to be inserted to the output file
  $row = array();

  // generate the column values
  $row = explode(":",$key);

  // make the original value ($key) the first column
  array_unshift($row, $key);

  // return the array. some other function will fputcsv it
  return $row;
}

別の例として、ソース ファイルに次のような値の行が含まれている場合があります。

[prefix]:[url]

出力ファイルの列の値は次のようになります。

  • column1 = 完全な元の値 (常にこれになります)
  • 列 2 =[prefix]
  • column3 = [URL]
  • column4 = URL のドメインの [url] を解析します
  • column5 = ファイル拡張子の解析 [url]

だから私はこれらのことをするために書いgenerateRow()ています。

よし、これで全部揃った。それはすべて光沢があり、うまく機能しています。独自のファイルを受け取り、定義されたルールに基づいて列を含む新しいファイルを生成する新しい「プロセス」を作成する要求を受け取ります。私が実際に何を望んでいるかを皆さんがより簡単に理解できるように、これを文脈に入れるためのバックストーリーとしてこれらすべてを提供したかっただけです.

generateRow()したがって、「問題」は、現状では、「プロセス」が仕様に基づいて書き出すコーダー (私) によって作成されていることです。これは、私や PHP を知っている他の人にとって特に難しいことではありません。しかし、特定の利害関係者が自分でこのようなものを作成することを担当したいという点で、これは「ユーザーフレンドリー」ではありませんが、彼らはコーダーではありません.

したがって、私の仕事は、基本的に の Web インターフェイスを提供することですgenerateRow()。したがって、基本的には、以前に選択したアイテムに基づいてフォーム要素と可能なオプションを動的に生成するフォームを作成する必要があります。つまり、表現エンジンです。または述語エンジン。またはルールビルダー。正直なところ、これらの用語のどれが最も正確であるかは 100% 確信が持てませんが、私は多くのグーグル検索と読書を行ってきました。

したがって、たとえば、フォームはユーザーに条件または代入式を作成するように求めることから始まります。

[ドロップダウン:if|設定]

IF:ユーザーが「if」をクリックすると、別のドロップダウンが表示され、チェック対象の「変数」のリストが表示されます。たとえば、システムは、他の列、ソース ファイルの任意の列 (キーを含む)、インポート ファイル名、またはユーザーが以前に作成した任意のカスタム変数 (以下の「設定」を参照) への参照を選択として使用できます。フォームには「アクション」ドロップダウンが表示され、「設定されている」、「設定されていない」、「より大きい」、「正規表現」などを表示します。ユーザーが「設定されている」または「設定されていない」などを選択すると、他のフィールドは出力されません。ただし、ユーザーがたとえば「より大きい」を選択すると、別のドロップダウンが表示され、「変数」のリストから選択するか、値を入力する入力フィールドが求められます。

IF column1 "is set"           /* check if column1 is set */
IF column1 contains "foobar"  /* check if column1 contains "foobar" */
If column1 regex "^[a-z]+$"   /* check if column1 contains only letters */

これが定義されると、ユーザーはその中に「set」式を追加できます。簡単にするために、条件をネストしたり、AND | OR を使用して複合条件を作成したりする必要はないと思います。

SET:したがって、ユーザーがこのオプションを選択すると、フォームは代入式の作成をガイドします。最初のドロップダウンには、出力ファイルの列など、ユーザーが値を割り当てることができる変数、または一時変数が保持されるため、他の式で参照できます。例:

SET [column1] [=] ["foobar"]
SET [column2] [=] [column1]
SET [column1] [regex] [userVar1] ["^[^:]+"]
SET [userVar1] [explode] [key] [":"] 

それが「最良の」提示方法であるかどうかはわかりませんが、うまくいけば、アイデアが得られることを願っています.

次に、これらの式を保存してから、それらを評価するための PHP コードを記述します。基本的にそれらを実際のphpコードに変換します。その部分に関しては、実際には問題ないと思います。インタープリターパターンを使用するだけです。

しかし、私が助けを必要としているのは、「マッピング」/「ビルダー」部分の表現全体です。実際、可能性のある表現の「マッピング」を肉付けできれば、「ビルダー」の部分もスイングできると思います。

そうそう、私の質問の核心はここにあります。可能な表現をどのようにマッピングするかです。現在、私はそれをxmlとして構造化/マッピングしようとして遊んでいますが、可能なすべてのパスをハードコーディングするだけで、その方法を把握できないようです。まず、私にはこれは効率が悪いように思えます。よりスマートな方法があるはずです。おそらく簡単に拡張することはできません...「プロセス」#1のルールセットには、描画する2つのソースファイル列と生成する5つの出力ファイル列があるとしましょう..そして「プロセス」#2は1と4ですか?ユーザーが設定できる可変量のユーザー定義変数の説明についてはどうですか。

それで、この種のことを行う方法を説明するヒントやリンクを持っている人はいますか? または、プレハブ(php)ソリューションがあればさらに良いですが、まだ何かを見つけることができませんでした..

編集:これは私が今いる場所の例です。うまくいけば、私の問題をよりよく理解できるようになります。

たとえば、マップ (xml) をハードコーディングした場合、次のようになります。

<expressions>
  <expression type='if'>
    <variable name='column1'>
      <operator type='isset'></operator>
      <operator type='notset'></operator> 
      <operator type='equals'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
      <operator type='greaterThan'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
      <operator type='lessThan'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
    </variable>
    <variable name='column2'>
      <operator type='equals'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
      <operator type='greaterThan'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
      <operator type='lessThan'>
        <variable name='column1' />
        <variable name='column2' />
        <variable name='column3' />
      </operator>
    </variable>
</expressions>

カップルのメモ:

  1. 任意の数のvariableノードがあります。ソースファイルの列ごとに 1 つ、出力ファイルの列名ごとに 1 つ、ユーザーがその場で作成する変数ごとに 1 つ、などです。
  2. 可変数のoperatorタイプがあります。3つの例を示しましたが、これまでに20ほど思いついたものがあります
  3. 一部のoperatorタイプでは、追加のフォーム フィールドをフォームに出力する必要があることに注意してください。たとえば、「if [column1] [isset]」対「if [column1] [greaterThan] [column2]」
  4. このexpressionノードは、「if」式がどのようになるかを示しています。またexpression、異なる構造を持つ「セット」タイプのノードもありますが、原理的には同じように機能します。たとえば、「[set] [column2] [equals] [column1]」または「[set] [column1] [regex] [sourceColumn1] [input value (regex)]」という式が存在する可能性があります。

そのため、今はパスをたどって、ツリーを下っていく利用可能なものに基づいてメニューを動的に構築することができます。

しかし、ご覧のとおり、繰り返しが多いように見えます。また、新しいもの (新しいオペレーターなど) をミックスに投入するのはピタリです。ここでの質問は、これをより適切に構成するにはどうすればよいかということです。それとも、それは不可能であり、唯一の解決策はすべての可能性をハードコーディングすることですか?

4

3 に答える 3

3

うわー、これは素晴らしい質問です!直接の質問への回答から始めて、一般的な問題に触れます。

このための既製の製品が必要な場合は、3dfacto や Drools などの「製品構成」システムがあり、一連のルール (この場合は、システムのルールがどのように構築されるかのルール) を取り、動的なフォームを作成できます。有効なルールの入力のみを許可します。実際には、上で書いた XML と大差ありません。何が起こっているのか見てみましょう:

まず、システム内のルールを表現する言語を定義しています。言語の構造は文法と呼ばれ、通常は BNF を使用して文法を記述します。例えば:

command := <if> | <set>
if := "if" <boolexpr> "then" <command>
boolexpr := <column> isset |
            <column> notset | 
            <column> "greaterThan" <column> |
            <column> "lessThan" <column>
<column> := "column1" | "column2" | ... | "column_n"
set := <column> <equals> <value> | ...
value := <column> | <number>

文法の一部にはコードが必要になる場合があることに注意してください。たとえば、「列」の部分は、実際の列の数に応じて動的です。多くのコードが混在していますが、Drools ルール エンジンの文法を見ることができます。

文法の BNF 表現と XML マップの主な違いは、あなたが思いついたもの、つまり前方リンクと後方リンクです。この 2 つはまったく同じものを表していますが、BNF は XML よりコンパクトです。これは、サブ構造をそのままコピーするのではなく、参照できるためです。たとえば、それが<value>列であるかリテラルの数値であるかに関係なく、どこでもルールを使用できます。別の考え方としては、ルールの数よりも多くのパスがルールを通過するということです。

コードで文法をどのように表現するか? 1 つの方法は、配列を使用することです。

$column = a_function
$boolexpr = Array("or", Array("match", $column, "isset"), Array("match", $column, "notset"), Array("match", $column, "greatherthan", $column), Array("match", $column, "lessthan", $column))
$command_grammar = Array("match", "If", $boolexpr, "then", $command)

フォーム ビルダー システムは基本的に、この文法を抽象的に解釈します。あなたは尋ねています:「この時点までの入力を与えると、有効な次の入力は何ですか?」そして、これまでに入力したルールを使用して文法を解釈し、次に何が来るかを確認することによってそれを行います。「インタープリター」パターンについて言及したので、これに精通していると思います。

それを考える別の方法は、パーサーを作成していることです。通常、パーサーは、入力との照合を試みる文法規則を介して可能なすべてのパスを試行し、次の場合にすぐにパスを拒否します。

  1. これまでの入力とパスは異なります
  2. パスは終了しましたが、さらに入力が残っています。
  3. 入力は終了しましたが、パスに沿ってさらに空でない文法規則があります。

あなたのシステムでは、無効なルールの入力を許可していないため、(1) と (2) が発生することはありません。(3) ユーザーが規則を完全に指定していないために発生する可能性があるため、フォームを更新するために次に来る文法規則を調べることができます。

一歩下がって、私たちがやろうとしていることを見てみましょう: 非プログラマーがコンピューターをプログラムできるようにします。よくある問題の 1 つは、そのようなシステムを柔軟にしようとすると、システムが独自のプログラミング言語になってしまうことです。通常、それらは既存の言語よりも劣っており、それを使用するにはプログラマーである必要があります。「または」は複雑すぎるなど、いくつかのことを言うことで正しい考えを持っていると思います。複雑さを制限することで、このチューリング ターピットを回避できます。

この問題を回避するもう 1 つの方法は、PHP などの既存の言語を活用することです。タスクを簡単にする関数を定義し、例をガイドとして使用してエンドユーザーに直接 PHP を記述させることができます。ここでは継続的なフィードバックが役立ちます。このアプローチの例については、Processingをご覧ください。

于 2013-10-11T20:56:52.700 に答える
1

OKAY、私が理解しているように、ルール生成システムが必要なので、ユーザーはメインの文字列またはファイルを送信し、彼が望むものを言います。次に、ルールジェネレーターがユーザーの希望に基づいてルールを作成し、それらをルールとして generateRow() に送信し、次に generateRow () 値を返します。

1- u が言ったように、equal、GT、LT、contains、regExp などの主要な演算規則を可能な配列として定義し、型に合わせてグループ化する必要があります。ここには、string と numbers という 2 つの操作規則グループがあります。次に、このグループとメモを使用して xml ファイルを作成します。次のようなすべての演算子をメモします。

<strings>
 <oprator>
  <title>equal</title>
  <php_func>stristr</php_func>
  <input_arg_count>2</input_arg_count>
  <true_return>true</true_return>
 </oprator>

 <oprator>
  <title>not_in</title>
  <php_func>stristr</php_func>
  <input_arg_count>2</input_arg_count>
  <true_return>false</true_return>
 </oprator>

</string>

3-入力ファイルのタイプ、パイルまたは列ベース、列ベースの場合、列区切り文字、例、または|をユーザーに尋ねる必要があります。また :

2- ユーザー インターフェイスでは、操作中の列の種類を確認する必要があります。たとえば、col1 タイプ: 文字列。col2 type : int (ユーザー入力が cols に基づく場合)。それ以外の場合、ユーザー入力ファイルが単なるファイルの場合、ルール ジェネレーターは string に設定する必要があります。それ以外の場合は、特別なルール group by user set data に設定する必要があります。たとえば、col1 が string の場合、可能な演算子を文字列演算子に設定し、ユーザー文字列演算子を表示します。

3- 一部の演算子には 2 つの入力引数 (input_arg_count) が必要です。そのため、この操作でどの列を操作する必要があるかについて、列を分割する必要があります。

4- すべてのユーザー ルールを入力とともに収集し (文字列を使用することをお勧めします)、操作文字列としてルール ジェネレーターに送信する必要があります。

操作文字列を分割する 5- ルール ジェネレーター (定義済みの分割線による) で、スイッチでルールを作成します。

6- スイッチ : このスイッチでは、ユーザー入力ファイルの種類を確認する必要があります。はあります | そのため、| でファイルを分割できます。、それからあなたはcolベースのファイルを持っています。これにより、操作が再利用されます

7-次に、操作の種類を確認します。そのため、可能性のある oprators xml ファイルで、操作の種類を理解できます。そして、オペレーターを配列として取得し、別の引数としてオペレーターを取得するメイン関数を作成し、最後の引数として、可能なオペレーターxmlファイルから使用可能なphp関数を取得します。そのため、システムはどの関数、どの演算子、および引数になります。

8-最初の操作のresulatを返した後。ループ関数のように、次の操作に送信するため、操作は操作されます。

あなたはそれをgitハブに入れることができるので、私はあなたがそれを開発するのを手伝うことができます.

幸運を

于 2013-10-10T14:01:06.273 に答える
0

あなたの例のように、元の値が常に文字列であり、生成された値が常に文字列のみから控除できるように、ルールが常にその文字列にいくつかの変更を加えている場合、機械学習のアプローチについて考えましたか? ユーザーに元の値と生成された値の例を記入してもらい、アルゴリズムは例からルールを推測しようとすることができます。

このペーパーは、あなたが望むようなことをしているようです (ただし、おそらくもう少し複雑です。すべてのルールが基本的に正規表現である場合は、より簡単になる可能性があります)。

このオプションはスケーラブルである必要があり、適切なアルゴリズムを見つけることができれば、忙しい仕事をする必要性を最小限に抑えることができますが、完璧ではありません。手書きが必要な複雑なルール。

于 2013-10-12T02:09:22.030 に答える