好的,首先,对不起 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]
- 列 3 = [网址]
- column4 = 为 url 的域解析 [url]
- column5 = 为文件扩展名解析 [url]
所以我写信generateRow()
来做这些事情。
好的,我拥有这一切。这一切都很闪亮,工作得很好。我收到创建新“进程”的请求,这些“进程”接收自己的文件并根据定义的规则生成带有列的新文件。我只是想提供所有这些作为背景故事,以便将其置于上下文中,以便你们更容易理解我真正想要的东西。
所以“问题”是,就目前而言,“过程”是由编码员(我)generateRow()
根据规范写出来的。这对我自己或任何了解 php 的人来说都不是特别困难。但这不是“用户友好的”,因为某些利益相关者希望自己负责创建这些东西,但他们不是编码人员。
所以我现在的任务是基本上为generateRow()
. 所以在我看来,我基本上需要制作一个表单,根据之前选择的项目动态生成表单元素和可能的选项。换句话说,一个表达式引擎。或谓词引擎。或规则生成器。老实说,我不能 100% 确定这些术语中哪一个(如果有的话)是最准确的,但我一直在进行大量的谷歌搜索和阅读,到目前为止,这些都是我想出的。
例如,表单会从要求用户创建条件或赋值表达式开始,
[下拉:如果|设置]
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?如何考虑用户可以设置的可变数量的用户定义变量。
那么,有没有人有任何提示或链接到 tuts 解释如何做这种事情?或者更好的是预制(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>
情侣笔记:
- 有任意数量的
variable
节点。每个源文件列都有一个,每个输出文件列名一个,用户动态创建的每个变量一个,等等。 - 有可变数量的
operator
类型。我只展示了 3 个示例,但到目前为止,我已经想到了 20 个 - 请注意某些
operator
类型如何需要在表单上输出额外的表单字段。例如,“if [column1] [isset]”与“if [column1] [greaterThan] [column2]” - 该
expression
节点显示“if”表达式的外观。还有一个expression
“set”类型的节点,它具有不同的结构,但原则上工作相同。例如,可能有一个表达式“[set] [column2] [equals] [column1]”或“[set] [column1] [regex] [sourceColumn1] [input value (regex)]”
所以现在我可以沿着路径走下去,根据树下可用的内容动态构建菜单。
但正如您所看到的,似乎有很多重复,而且将新事物加入混合(如新运算符)也将是一个皮塔饼。所以这里的问题是,我将如何更好地构建它?或者它只是不可能,唯一的解决方案是硬编码每一种可能性?