表达式管理器
From LimeSurvey Manual
快速入门教程
综述
在自定义调查时,你通常需要一种方法来指定以下内容:
- 导航/分支 - 根据主题答案改变问题的顺序
- 裁剪(Tailoring)/管道(Piping) - 如何表达问题(例如提及先前的答案,或根据你的主题的数量或性别来结合句子),或如何生成自定义报告(如评估分数或量身定制的建议)。
- 验证 - 确保答案通过某些条件,如最小值和最大值,或匹配输入模式
表达式管理器(EM)提供了一种直观的方法来指定每个功能的逻辑。即使你正在调用函数,几乎任何你可以写成标准数学方程的东西都是有效的表达式。 EM目前提供对70种函数的访问,并且可以轻松扩展以支持更多函数。它还允许你使用人类可读的变量名称(而不是SGQA名称)访问变量。
以下部分显示了使用表达式管理器的主要位置
相关性(控制导航/分支)
一些调查使用“跳转逻辑(Goto Logic)”,这样如果你用选项C回答问题1,那么就会跳到问题5。这种方法非常有限,因为很难验证,并且当你必须对问题进行重新排序时容易中断。 表达式管理器(EM)使用布尔相关性方程来指定问题可能有效的所有条件。如果问题是相关的,则显示问题,否则它不适用,并且将空值NULL存储在数据库中。这类似于可以通过条件编辑器完成的操作,但表达式管理器可以让你轻松指定更复杂和更强大的准则(并允许你使用变量名而不是SGQA命名)。
此图像显示了一种审查调查的相关性逻辑的方法。它计算体重指数(BMI)。关联方程式在变量名称后面的方括号中显示(以绿色显示)。因此,weight,weight_units,height和height_units的相关性都是1,这意味着总是会问这些问题。然而,BMI的相关性是{!is_empty(height) and !is_empty(weight)},这意味着只有当受试者输入身高和体重的值时才会计算BMI(从而避免除以零出错的风险)。此外,仅当主题回答所有四个主要问题(身高,身高,体重,体重,体重_单位)时,才会显示报告问题。
相关性在以下位置显示和编辑:
查看/编辑问题级别相关性
该等式计算体重指数(BMI)。只询问该人是否第一次输入他们的身高和体重。
这是BMI问题的编辑屏幕。
请注意,输入相关性方程时不要使用花括号。
查看/编辑组级相关性
这是一次简单的人口普查。第一页询问有多少人和你住在一起并将其存储在“cohabs”变量中。只有当你有多个同居者时才会显示此页面(因此会显示第二个与你同居的人),并且仅显示你是否指定了第一人与你的关系(p1_rel)。
如你所见,该组还具有问题级别的相关性标准,这样每个问题只有在你回答之前的问题后才会出现(例如{!is_empty(p1_sex)})。 表达式管理器结合了群组和问题级别的相关性。仅询问组中的问题是否与整个组相关。然后,仅询问组内相关的问题子集。
以下是用于编辑该问题的组级相关性的屏幕:
请注意,输入相关性方程时不要使用花括号。
裁剪(Tailoring)/管道(Piping)
表达式管理器可让你轻松地对问题进行简单而复杂的条件定制。有时你只需要简单的替换,比如说,“您购买了 [ 产品]。您最喜欢它的是什么?“。有时你需要条件替换,比如” [ 名字] [ 先生/女士] ,您愿意完成我们的调查吗?“。在这种情况下,你想根据个人的性别使用先生或女士。其他时候你需要更复杂的替代(例如基于数学计算)。表达式管理器支持这些类型的裁剪/管道。
条件方程式
身体质量指数示例显示了计算人的BMI的能力,即使让他们以公制或非公制单位输入他们的身高和体重。
这里weight_kg是{if(weight_units == 'kg', weight, weight * .453592)}。这个if()函数意味着如果受试者使用公斤输入重量,则使用该值,否则将输入的值(以磅为单位)乘以.453592将其转换为公斤。 height_m变量使用类似的方法计算人的身高(以米为单位),即使他以英寸为单位输入身高。
BMI的权重计算公式为{weight_kg / (height_m * height_m)}。
最后,该报告有条不紊地裁剪了主题的信息,告诉对方他输入了什么。 (“您的身高为2米,体重为70公斤。”)
尽管上图中没有很好地显示,但weight_status使用嵌套的if()语句将人分类为体重不足至严重肥胖。你可以在问卷逻辑视图(Show Logic View)中看到它的等式
在这个问题的编辑窗口中,你可以看到两件事:
- 裁剪(Tailoring)必须用花括号包围表达式
- 如果要使嵌套的条件逻辑更易于阅读, 则表达式可以跨越多行。
定制的(Tailored)问题,答案和报告
此示例显示BMI报告。
这是同一问题的编辑窗口。
如你所见,花括号中的任何内容都被视为表达式,因此在前面的图像中以语法突出显示(颜色编码)。如果你有任何拼写错误(例如拼写错误或未定义的变量名称或函数),表达式管理器会显示错误,例如,显示height_unit是未定义的变量名称(实际上是height_units),而rnd()是未定义的函数(正确的函数名称是round())。在这两种情况下,错误都被红色框包围,以便更容易发现并修复它们。
你还可以看到,你可以快速创建复杂的报告,例如输入值表或定制建议。
请记住,所有裁剪(tailoring)都必须包含带有花括号的表达式,以便LimeSurvey知道问题的哪些部分是自由文本,哪些部分应该通过表达式管理器进行解析。
验证
表达式管理器控制大多数高级问题选项的工作方式。这些控制如最小/最大答案数;最小/最大个体值;最小/最大总和值;并检查输入的值是否与指定的字符串模式匹配。你可以像往常一样继续输入这些高级问题选项。但是,现在其中一个字段中的任何值都被视为表达式,因此你可以使用与其他问题具有复杂条件关系的最小/最大条件。
在所有这些情况下,由于高级问题选项始终被视为表达式,因此在指定它时不使用花括号。
调查示例页面显示了许多使用表达式进行验证的工作示例。
简介
LimeSurvey使用新的表达式管理器(EM)模块,这将使LimeSurvey支持更复杂的分支,评估,验证和定制。它将取代LimeSurvey在后端如何管理替换,条件和评估。它还可以大大加快处理速度,因为它消除了大多数运行时的数据库读取。 EM由Thomas White博士(TMSWhite)开发。
此Wiki页面是Expression Manager语法和功能的权威参考。
关键定义
- 表达式(Expression):任何被花括号包围的东西
- 只要在开括号之后或闭合花括号之前没有空格
- 表达式的内容由表达式管理器(EM)评估,因此它们可以包含数学公式,函数以及复杂的字符串和日期处理。
- 裁剪(Tailoring):有时称为“管道(piping)”,这是过程有条件地修改文本
- 你可以访问所有“替换字段”,参与者数据和响应数据。
- 你还可以更轻松地访问问题,答案及其属性。
- 关联(Relevance)方程式:一个控制问题可见性的新问题属性
- 如果存在相关方程(relevance equation),那么仅在相关性评估为真时才显示问题。
- 在内部,所有array_filter和array_filter_exclude命令成为子问题级别的相关性
- 方程式(Equation)问题类型:一种新的问题类型,可以将计算或报告保存到数据库中
- 它就像一个样板文件(Boilerplate)问题,但即使你设置“始终隐藏此问题”,其内容也会保存到数据库中
- 问题代码:这是EM的首选变量名
- 这可以是一个描述性名称, 指示问题的目的, 使其更容易阅读复杂的逻辑
- 有效的问题代码不应该以数字开头,所以当使用问题代码为你的问题编号时,只需使用“q1” “,或”q1a“或”g1q2“。
- 如果你将数据导出到SPSS或R,那么这就是当前变量名称,因此如果你进行统计分析,你可能已经将此变为唯一。
我必须使用表达式管理器(EM)?
简单来说是 "否" (但也是 "是")。
EM完全向后兼容现有的调查。因此,如果你乐意在低于1.91+版本的LimeSurvey中使用条件和评估,你可以继续这样做。
但是,EM完全取代了LimeSurvey内部处理条件的方式。虽然你仍然可以使用条件编辑器来创建和管理条件,但LimeSurvey 1.92会将这些条件转换为等效的相关方程式。作为升级的一部分,LimeSurvey 1.92会将所有现有条件自动转换为相关方程式。
这应该可以为你提供两全其美的效果 - 你可以像以前一样继续使用LimeSurvey,但会看到相关等式,因此你可以在需要时直接逐渐迁移到相关方程式。
我可以混合使用条件和相关方程吗?
是。你可以将条件编辑器用于某些问题,将相关方程编辑器用于其他问题。保存问题时,条件会自动转换为相关方程。
注意,我们假设如果你正在使用条件编辑器,那么你希望这些条件覆盖任何手动输入的相关性方程式。因此,如果你有现有条件并想要手动编辑相关性,请先删除该问题的条件。具体来说,将生成的相关性方程式复制到文本编辑器,使用“条件”菜单删除该问题的所有条件(这也将删除相关方程),然后编辑问题并将生成的相关方程式从文本编辑器粘贴回该问题的相关性字段(并保存问题)。如果有足够的需求删除条件而不删除生成的相关方程式,我们可以添加批量转换过程。
如何在条件和相关性之间进行选择?
以下是每种方式的优缺点列表:
方式 | 优点 | 缺点 |
---|---|---|
条件 | 1.用于创建简单条件的精美GUI 2.GUI有良好的文档,并且便于理解 ,这一切都得益于支持团队 |
1.仅支持简单比较,并且不支持AND / OR条件 2.级联条件不规律地工作 3.缓慢 - 数据库密集,因此会减慢长期调查 4.一些人报告了重装条件的问题 5.当有数十,数百或数千个问题时,GUI不能很好地扩展 6.由于必须使用SGQA名称,因此转换基于纸张的调查可能会很慢 7.经常需要程序员自定义复杂分支所需的逻辑 |
相关性 | 1.支持非常复杂的逻辑,包括80多个函数和数学/字符串运算符 2.完美支持级联逻辑 3.快速 - 无需额外的数据库调用,因此支持1000多个问题调查 4.重新加载逻辑没有问题,因为不需要SGQA代码 5.语法突出显示缩放到1000多个问题调查 6.方便快捷地用于希望计算机化现有纸质调查的团体。 7.轻松支持半结构化访谈和流行病学调查,无需程序员 |
1.没有简单条件的GUI - 而是使用语法高亮 2.新的,所以支持团队尚未掌握EM。 |
最重要的是,如果你对LimeSurvey 1.91+的工作方式感到满意,则没有理由改变你的工作。
使用EM有哪些其他好处?
以下是你可能想要使用EM的其他一些原因。
- 计算(Calculations) - 你可以创建任何你能想到的计算:
- 你可以访问所有常见的数学运算符和函数
- 你可以访问70多个数学、日期和字符串处理函数
- 如果用户需要,开发人员可以很容易地添加新函数
- 将计算存储到数据库
- 你现在可以计算简单和复杂的算式和/或量表分数,并将它们存储在数据库中而无需JavaScript。
- 你可以使用方程式(Equation)问题类型来完成此任务。
- 评估(Assessments)
- 你现在可以创建任何问题类型的评估或量表分数,而不仅仅是过去支持的子集
- 你可以使用裁剪在任何需要的地方显示运行或总评估分数 - 即使在同一页面上
- 你有更多控制权基于这些评估分数生成的报告
- 你可以在不需要JavaScript的情况下将评估分数存储在数据库中
- 你可以隐藏评估分数而不需要JavaScript或CSS
- 替换字段(Replacement Fields)
- 你可以使用问题代码而不是使用{INSERTANS:SGQA} - 这使它更容易阅读并且验证。
- 这也避免了编辑问题以改变SGQA代码以使一切正常工作的常见需求。
- 裁剪(Tailoring) - 你可以根据其他值有条件地显示文本
- 使用适当的一个主题的标题,如(例如“您好,史密斯[先生/女士]。”)
- 基于单数/复数时输出格式正确的句子:(例如”你有1个孩子“与”你有2个孩子“)
- 根据主题的性别和多数来调整动词的形式和名词变格。
- 新变量属性 - 你可以访问以下内容进行剪裁:
- (无后缀) - qcode.code的别名
- .code - 相关问题的选定响应代码(如果它是相关的,否则为空白),或文本值(如果它不是编码问题)
- .NAOK - 与.code相同,但可以是计算或列表的一部分即使不相关
- .value - 问题的评估值(如果它是相关的,否则为空白),或文本值,如果它不是编码问题
- .valueNAOK - 与.value相同,但是即使不相关也可以成为计算或列表的一部分
- .show - 显示给用户的答案(这是{INSERTANS:xxx}所做的)
- .qid - 问题ID
- .gid - 组ID
- .sgqa - 问题的SGQA值
- .jsName - 问题的正确javascript变量名,无论是否在此页面上定义
- .qseq - 问题序列(从0开始)
- .gseq - 组序列(从0开始)
- .mandatory - 问题是否是强制性的(是/否)
- .question - 问题的文本
- .relevance - 该问题的相关性方程式
- .gllevance - 该组的相关性方程式
- .intelationsationStatus - 当前问题是否相关(如果为真则为1,如果为假则为0)
- .type - 问题类型(一个字符代码)
- 动态页面更改
- 所有相关性,计算和裁剪在页面上动态工作 - 因此值的更改会立即更新页面
- 所以,你有问题根据它们是否相关而动态显示/消失
- 问题也是根据页面上的响应动态定制的,因此你可以看到运行总计,量身定制的句子和自定义报告。
- 新的数据输入屏幕
- 除了使用当前的数据录入系统外,你还可以使用Survey-All-In-One。
- 这支持页面相关性和剪裁,因此数据录入员可以快速完成选项卡通过,他们只需要输入相关的回复
- 如果你的数据输入人员需要查看剪裁,这也是动态的,这可能是至关重要的。
- 消除了对大多数自定义JavaScript的需求
- EM很容易支持复杂的计算,评分,剪裁和条件逻辑。
- 有些东西仍然需要JavaScript(比如自定义布局和有条件隐藏的问题子元素),但是你的JavaScript可以使用EM函数,这样你可以通过Qcode而不是SGQA访问问题,并访问上面列出的任何问题属性。
EM启用了哪些其他有用的新功能?
无论你是继续使用条件编辑器还是手动构建相关方程式,你都可以获得以下额外好处:
- 你可以创建更复杂的验证标准
- 所有高级问题属性(如max_answers,min_num_value_n, max_num_value)可以使用表达式。因此,你可以根据先前的响应轻松调整最小/最大标准,即使它们位于同一页面上。
- EM还处理所有基于正则表达式的验证,因此你可以强大地组合preg和equation-基于问题属性。
- 方便地重新排序(或删除)问题和组
- 在版本1.92之前,如果LimeSurvey认为重新排序可能会破坏被使用的条件,则无法重新排序问题或组。同样,如果有任何其他问题依赖于它们,则无法删除问题。
- 使用EM的语法突出显示,很容易看到并验证你是否在声明之前尝试使用问题。因此,我们现在允许你随时重新排序或删除问题和群组。 EM将更新所有语法突出显示以显示潜在错误。
- 重新排序问题视图已得到增强,以帮助进行此类审核。它现在显示问题的相关性方程和剪裁,因此你可以立即查看是否有任何变量变为粉红色(意味着它们在被声明之前使用)。
- 问题/组导航索引始终可用且准确
- 在版本1.92之前,如果有复杂的条件,这些索引不可用
- 使用EM,我们可以保证它们是准确的。
- 主题甚至可以跳回到先前的问题,更改答案然后向前跳(或提交)
- 当向前跳时,EM将重新验证所有介入的问题/组。
- 如果任何问题变得无关紧要,它们将在数据库中为空因此,你的数据在内部是一致的
- 如果任何问题变得相关或新的失败强制或验证规则,EM将停在该页面上并强制用户在跳到最终目的地之前回答这些问题。
- 自动将条件转换为相关性
- 升级数据库时,所有现有的调查具有条件的条件将为它们生成关联方程式
- 每当你导入调查时,将根据需要创建关联方程式
- 无论何时添加,删除或修改条件,EM都将生成相应的关联方程。
- 方便的语法突出显示
- 当EM显示相关性方程式时,它将显示Qcode,即使你输入了SGQA代码,因为我们认为这将更容易阅读。
- 全部变量采用颜色编码,以显示它们是在当前问题之前还是之后(或当前组之前或之后)声明的。这使你可以快速检测并修复在声明变量之前尝试使用变量进行相关性(包括array_filter),定制或验证方程式的情况。
- 此外,如果将鼠标悬停在颜色编码变量上,你将看到有关该问题的最重要的元数据。这包括组序列#,问题序列#,Qcode,问题文本和所有可用答案选项(如果它是具有枚举答案选项的问题类型)。
- 答案选项列表使用此语法: 'answers':{key:val, ... }.。
- key的语法为'scale~code''scale是答案量表(例如,对于双比例),代码是答案代码。
- val的语法'value~shown'其中value是评估值(如果使用评估,否则代码)(例如Qcode.value),shown是主题看到的显示值(例如Qcode.shown)
- 这意味着许多调查可以使用计算而无需评估模式。如果你有枚举唯一,非小数和非负数的答案选项,你可以简单地对Qcode.code值进行计算。
- 简单评估整个调查逻辑和内容
- 有一个新的显示问卷逻辑(Show Survey Logic)功能,可让你在一个页面上查看有关调查(或组或问题)的所有内容。
- 显示所选范围的组、问题、子问题和答案级别详细信息(调查与群组与问题)
- 它还显示相关性,子问题级别相关性(对于array_filter和array_filter_exclude),以及生成的验证方程式(对于preg和任何验证规则,如最小值/最大值和数量)所有非空白问题属性。
- 所有内容都是语法突出显示的,这样你就可以看到潜在的语法错误(比如不平衡的括号或在声明它们之前使用变量)
- 语法 - 高亮显示支持快速导航和编辑调查。
- 如果你点击一个变量名,它会打开一个浏览器窗口(或标签),显示该问题,并允许你编辑它。
- 如果你单击组名称,它将打开一个浏览器窗口(或选项卡),显示组重新排序视图,以便你可以轻松移动问题。
- 所有问题属性也都是语法突出显示。这使你可以在高级问题选项中设置和查看表达式(例如基于表达式的最大/最小数量/值的总和)
- EM作者使用类似的视图(更清洁一点)让他的合作流行病学家和机构审核委员会在高度分支和量身定制的结构化访谈中验证并授权调查数千个问题
入门
开始使用EM的最佳方法是:
- 从http://www.limesurvey.org/en/download安装最新的稳定版本
- 导入并探索示例调查。
- 探索用例和HowTos和分步示例。
- 浏览EM文档(本页)
- 检查内置的EM测试套件
- 从任何调查,在工具下,选择EM选项
- 可用功能列出70多种函数和语法
- 单元测试隔离表达式
- 显示了使用所有EM函数和运算符的示例,以及PHP和JavaScript结果
- 注意,很少有函数在PHP和JavaScript版本中生成不同的结果,因此该页面允许你相应地计划你的EM逻辑。
表达式管理器扩展/替换的功能是什么? (LimeSurvey <= 1.91 +)
条件 => 相关性
条件控制哪些问题可见。一般语法是SGQA operator Value,比如111X2X3 ==“Y”。条件可以进行AND运算或OR运算,但混合AND和OR很困难。条件本身存储在一个单独的表中,LimeSurvey的大部分代码专门用于管理条件。由于广泛的数据库访问,处理大量条件可能会导致显著的性能问题。此外,一旦你将条件分配给问题或组,你通常不被允许重新排序或删除它们。
Assessments =>方程式和微裁剪
评估使用户可以从一组问题中创建比例分数。但是,它们无法在当前页面上动态更改,并且它们的值未存储到数据库中。
替换=>微裁剪
用户可以根据之前的响应定制一些消息和问题。例如,一个问题可能是{TOKEN:FIRSTNAME},而{INSERTANS:111X3X4}是你最喜欢的运动。然而,不可能做有条件的剪裁(比如说“先生”或“太太”取决于人的性别),或者没有花哨的JavaScript的共轭动词或拒绝名词。作者可以实施似乎可以定制问题的调查,但是每个排列需要单独的问题,并且需要复杂的条件来决定要显示哪些问题。
验证
可以使用正则表达式或最小值/最大值验证问题,或者让SGQA响应作为最小值或最大值。但是,如果没有异常复杂的JavaScript,验证不能基于其他变量的计算。
方程式
没有异常复杂的JavaScript,方程式将不被支持。
方程式问题类型
没有异常复杂的JavaScript,方程式无法保存到数据库中(例如评估的最终得分)。
表达式管理器将如何替换/扩展该功能?
表达式管理器是LimeSurvey中的一个新核心模块,它使得支持过去需要自定义JavaScript的复杂功能类型变得更加容易。它也取代了LimeSurvey目前管理条件和评估的方式。
引用表达式管理器(EM)时的新术语
EM以下列术语“思考”其功能:
- 基于相关性的分支 - 如果问题是相关的,则问它,否则不要(例如使其隐形,并标记它)在数据库中为NULL)。所有问题类型以及每个组都有一个新的相关性字段(因此你可以将一组条件应用于整个组,而无需将相同条件复制到每个问题,和/或组合组和问题级条件逻辑)。
- '剪裁 - 一旦你知道应该问哪些问题,剪裁(有时称为管道)指定如何询问问题。这样,你不仅可以支持简单的替换(如{TOKEN:FIRSTNAME}),还可以根据你的主题的性别或数量来支持动词的结合和名词的下降。它还允许你根据他们是否回答(或他们如何回答)其他问题来更改您传递给主题的信息。
- 方程式 - EM添加一个名为Equation的新问题类型,用于存储结果一个表达。即使你在页面上隐藏它们,也会计算这些方程式结果并将其写入数据库。因此,它们可用于隐藏评分计算,基于复杂方程的导航,评估以及应在数据库中轻松获得的报告。
相关性和级联相关性
每个问题类型现在都有一个相关性选项,用于控制是否显示问题。 EM按照它们应该出现在调查中的顺序处理每个相关方程。如果表达式为真(或缺失 - 支持旧版调查),则会显示问题。如果它不相关,则将隐藏该问题,并且该值将在数据库中为NULL。如果组中没有相关问题,则将跳过整个组。
此外,如果表达式中的任何变量不相关,则表达式始终求值为false。这启用了级联相关性,因此你不必为每个问题编写非常长的相关性方程式。
假设你有Q1-Q5的5个问题,并且你只想在Q1被回答时显示Q2,如果Q2被回答则显示Q3等。相关性等式可能是:
问题代码 | 相关性 | 问题 |
---|---|---|
Q1 | 1 | 你叫什么名字? |
Q2 | Q1 | {Q1},你多大了? |
Q3 | Q2 | 所以,你是{Q2}岁。你结婚了吗? |
Q4 | Q3 ==“Y” | {Q1},你结婚多久了? |
Q5 | Q4 | 你有几个孩子,{Q1}? |
相关性计算也适用于JavaScript - 因此你可以将所有上述问题放在一个页面上,它仍然可以按预期工作。实际上,EM完全取代了EM处理调查与组与一次调查问卷调查格式的方式。他们现在都使用完全相同的导航引擎,因此无论调查风格如何,它们的工作方式相同。
只要你在同一页面上,你输入的任何数据仍然会存在,只是隐藏了。因此,如果你输入一些信息,然后选择一个使它们无关紧要的选项,然后再次使它们相关,你的答案仍然可用。但是,只要你移动到其他页面,所有不相关的响应都将丢失到数据集的完整性。
组级相关性
表达式管理器还支持组级相关性。这样可以更轻松地实现循环。假设你要收集有关多达10个实体(此类产品或家庭中的人)的信息,你首先要确定需要跟进的实体数量(例如询问有多少人居住在家中,或让人们检查从长长的名单中他们喜欢哪些产品)。在知道有多少实体需要跟进后,你可以使用组级别相关性,例如{count> = 1},{count> = 2},... {count> = 10},对于以下10组中的每一组都是如此问题。在每个组中,你可以使用问题级条件逻辑(例如针对每个主题的性别或年龄特定的后续问题)。将问题和组级相关性方程式进行AND运算以确定应显示哪个。
裁剪(Tailoring)/管道(Piping)
花括号内的任何内容现在都被视为表达式(下面有一个例外)。表达式适用于所有LimeReplacementFields,所有变量(通过几个别名),所有典型的方程式运算符(数学,逻辑和比较),以及许多函数(甚至可以在客户端动态工作)。
使用这些方程式,您可以执行以下操作:
- 根据先前的响应, 有条件地向响应者显示量身定制的消息
- 创建评估并根据这些结果显示评估结果 (或有条件地分支或显示消息), 而无需使用评估模块本身
- 在问题、答案和报告中结合动词和拒绝名词。
- 在调查结束时显示“显示您的答案”页面之前的答复摘要
方程式
有一种叫做方程式的新问题类型。它就像一个Boilerplate问题,除了它存储数据库中显示的内容的值。因此,如果方程问题文本包含评估计算,则该值将存储在数据库中的变量中,该变量可以在公共或私有统计信息中显示。
这解决了在数据库中存储评估分数的常见请求
语法
花括号中包含的任何内容现在都被视为一个表达式(有一个例外:必须没有前导或尾随空格 - 这是确保表达式管理器不会尝试处理嵌入式JavaScript所必需的)。
注意,表达式可以跨越多行,只要在开始大括号之后或结束大括号之前没有空格。这对于嵌套的if()语句特别有用:
{if(is_empty(PFTotals),
'',
if(PFTotals >= -5 && PFTotals <= -4,
'Very Soft',
if(PFTotals >= -3 && PFTotals <= -2,
'Soft',
if(PFTotals == -1,
'Somewhat Soft',
if(PFTotals == 0,
'Moderate',
if(PFTotals == 1,
'Somewhat Hard',
if(PFTotals >= 2 && PFTotals <= 3,
'Hard',
if(PFTotals >= 4 && PFTotals <= 5,
'Very Hard',
''
)
)
)
)
)
)
)
)}
- 所有标准数学运算符(例如+, - ,*,/,!)
- 所有标准比较运算符(例如<,<=,==,!=,>,> =,加上这些等价物: lt,le,eq,ne,gt,ge)
- 圆括号(所以你可以将子表达式分组)
- 条件运算符(例如&&,| |和这些等价物:和,或者)
- 单引号和双引号字符串(每个字符串可以用其他引号类型嵌入字符串)
- 逗号运算符(因此可以有一个表达式列表,只返回最终结果)
- 赋值运算符(=)
- 预定义变量(用于指代问题,问题属性和响应) - 例如所有SGQA代码
- 预定义函数(已经有70多个,并且很容易添加更多)
运算符
EM语法遵循正常的运算符优先级:
等级 | 运算符 | 说明 |
---|---|---|
1 | () | 用于分组或调用函数的括号 |
2 | ! - + | 一元运算符:逻辑“非”,一元求反,一元加 |
3 | * / | 乘,除 |
4 | + - | 加 ,减 |
5 | < <= > >= lt le gt ge | 相对比较 |
6 | == != eq ne | 相等比较 |
7 | and | 逻辑“和” |
8 | or | 逻辑“或” |
9 | = | 赋值 |
10 | , | 逗号 |
Warning with plus operator (+)
注意,为了JavaScript和PHP之间的一致性,如果两个操作数都是数字,则加号运算符(+)会添加,但如果两个部分都是非数字字符串,则会进行连接。但是,我们建议使用join()函数进行连接,因为这会使你的意图更加清晰,并且如果你期望字符串而不是数字(或反之亦然),则可以避免意外结果。
Warning with mismatch between number and string and alphabetic comparison
When you want to compare value with relative or equality comparisons, pay attention to type mismatch. Value entered by user or answer code selected can be used as number if it's clearly a number.
If you surround one of the values with "
it will force the comparison as text (alphabetic compare). If you want to compare numerically, never surround the number with quotation marks, "
.
For example Q0.NAOK > "50"
is true if Q0.NAOK is a numeric question with 9 as value. This is because the operator >
will assume it's alphabetical compare and not numerical.
To be sure to compare integer value, you can use intval(Q0.NAOK) > 50
, just remember if Q0.NAOK is not a number (empty or a string), then intval(Q0.NAOK) == 0. To compare string value ("A" < "B") use strcmp directly : strcmp(Q0.NAOK,"B")
or strcmp(Q0.NAOK,"A5")
.
关于使用赋值运算符(=)的注意事项
注意,除非绝对必要,否则应避免使用赋值运算符,因为它们可能会导致意外的副作用。例如,如果你更改先前响应的值,则不会重新计算该问题与当前问题之间的级联相关性和验证逻辑,因此你最终可能会得到内部不一致的数据(例如,问题仍然可以得到解答但应该具有已被NULL,或者被跳过但应该已经回答的问题)。通常,如果要为变量赋值,则应创建方程式问题类型,并使用表达式设置其值。然而,人们真的需要这个运算符,但是我们很少有人能够使用它。
为了帮助提醒你这个操作符,它在语法方程中以红色字体显示(这样你就不会将它与“==”混淆)
使用赋值运算符
你可能想要使用赋值的主要原因是:
- 你需要通过等式设置不接受默认值的问题的默认值(例如列表单选,用户界面允许你选择一个答案选项,但不允许你输入等式)。但是,要小心,因为LimeSurvey将无法验证你的等式是否为该问题生成了允许的答案之一。
- 你需要根据以后的响应强制更改对先前问题的响应
等等……
您可以使用所有表达式管理器系统来实现此目的。为此目的,最好使用方程式问题类型。
一些例子:
- 用小写设置答案的短文本问题:
{QCODE=strtolower(QCODE.NAOK)}
- 在调查开始时设置数组问题类型的默认答案:
{Q1_SQ1=(is_empty(Q1_SQ1.NAOK),"A99",Q1_SQ1.NAOK)}
- 在调查开始时设置数组文本问题类型的默认答案:
{Q1_SQY1_SQX1 = (is_empty(Q1_SQY1_SQX1.NAOK),"Inserted answer", Q1_SQY1_SQX1.NAOK)}
- 用条件设置答案:
{QCODE=if(YesNo="Y","A1","")}
XSS安全
使用XSS启用时,不能使用某些表达式管理器系统:
- 在表达式中启动HTML标记但以另一个表达式结束
- 在URL中使用复杂表达式。
示例和解决方法
{if( 1 ,"<strong>","")}information{if( 1 ,"</strong>","")}
is broken with XSS security, here you can use{if(1,"<strong>information</strong>","information")}
<a href="/script.php?value={if(QCODE == "Y","yes","no")}">next</a>
, here you can use an equation question because using a complete question code is OK :<a href="/script.php?value={EQUATION.NAOK}">next</a>
访问变量
表达式管理器提供对我们可能需要的任何变量的只读访问权限。为了向后兼容,它提供对以下内容的访问:
- TOKEN:xxx - TOKEN的值(例如TOKEN:FIRSTNAME,TOKEN:ATTRIBUTE_5)(仅用于非匿名调查)。
- INSERTANS:SGQA - 答案的显示值(例如“是”)。对于Expression Manager,它与使用{QCODE.shown}相同。
- 所有{XXX} values used by templates。
- 在问题文本中,你可以使用{QID}替换由问题id和{SGQ}取代SGQA的问题
此外,表达式管理器允许你通过问题代码(数据库中问题表中的“标题”列)引用变量。这也是将数据导出到SPSS,R或SAS时使用的变量标签。例如,如果你对姓名,年龄和性别有疑问,可以将这些变量称为“姓名”,“年龄”和“性别”,而不是“12345X13X22”,“12345X13X23” '和12345X13X24。这使得每个人都可以更容易地阅读和验证逻辑,并且可以在不必跟踪组或问题数字的情况下随机调整问题。
重要:引用前几页或问题中出现的变量是安全的。
此外,表达式管理器允许你访问问题的许多属性:
语法 | 含义 | 示例 | 示例结果 |
---|---|---|---|
Qcode | Qcode.code的别名 | {implode(',',name,gender)} | 'Tom','M' |
Qcode.code | 选择的问题响应代码是否相关(否则为空白),或文本值(如果不是)编码问题 | {implode(',',name.code,gender.code)} | 'Tom','M' |
Qcode.NAOK | 与Qcode相同 - 请参阅讨论NAOK | {gender.NAOK} | 'M' |
Qcode.value | 问题的评估值是否相关(否则为空白),如果不是,则为文本值编码问题 | {gender.value} | '1' |
Qcode.valueNAOK | 问题的评估值是否相关(否则为空白),如果不是,则为文本值编码问题 | {gender.valueNAOK} | '1' |
Qcode.shown | 问题的显示值 | {implode(',',name.shown,gender.shown)} | 'Tom','Male' |
Qcode.question | 问题的文字 | {gender.question} | 'What is your gender?' |
Qcode.mandatory | 是否有问题是强制性的(是/否) | {gender.mandatory} | 'N' |
Qcode.qid | 内部问题编号(不是序号) | {gender.qid} | 337 |
Qcode.type | 问题类型 | {gender.type} | 'G' |
Qcode.jsName | 问题的正确javascript名称,无论是否在此页面上声明 | {gender.jsName} | 'java1827X3X337' |
Qcode.gid | the internal 内部组号(不是序号) | {gender.gid} | 3 |
Qcode.qseq | 问题的序号,从0开始 | {gender.qseq} | 5 |
Qcode.gseq | 组的序号,从0开始 | {gender.gseq} | 1 |
Qcode.relevanceStatus | 问题当前是否相关(0或1) | {gender.relevanceStatus} | 1 |
Qcode.relevance | 问题级相关方程式 | {gender.relevance} | '!is_empty(name)' |
Qcode.grelevance | 组级相关性方程式 | {gender.grelevance} | 'num_children >= 5' |
Qcode.sgqa | 此问题的SGQA值 | {gender.sgqa} | '1827X3X337' |
HTML编辑器问题
如果你使用HTML编辑器,则某些字符将被HTML实体替换。
- & by &
- < by <
- > by >
如果你使用HTML编辑器,则需要使用:
- and for &
- lt for <
- le for <=
- gt for >
- ge for >=
Qcode变量命名
以下是如何按问题类型构造Qcode(并访问某些属性)的详细信息。通常,Qcodes构造如下:
QuestionCode . '_' . SubQuestionID . '_' . ScaleId
对于评论和其他,问题代码是QuestionCode_comment和QuestionCode_other
类型 | 说明 | 代码 | 子问题 | 答案选项 | 比例 | 答案代码 | 答案显示 | 相关性 |
---|---|---|---|---|---|---|---|---|
5 | 5 Point Choice Radio-Buttons | Q1 | 1-5 | {Q1} | {Q1.shown} | {Q1==3} | ||
B | Array (10 Point Choice) Radio-Buttons | Q2 | L1-L6 | 1-10 | {Q2_L2} | {Q2_L2.shown} | {Q2_L2==7} | |
A | Array (5 Point Choice) Radio-Buttons | Q3 | 1-5 | 1-5 | {Q3_1} | {Q3_1.shown} | {Q3_1>=3} | |
1 | Array (Flexible Labels) Dual Scale | Q4 | sq1-sq5 | 0:a1-a3 | 1:b1-b3 | {Q4_sq1_0} | {Q4_sq1_1.shown} | {Q4_sq1_1=='b2'} |
H | Array (Flexible) - Column Format | Q5 | 1-5 | s,m,t | {Q5_1} | {Q5_1.shown} | {Q5_1=='s'} | |
F | Array (Flexible) - Row Format | Q6 | F1-F5 | 1-5 | {Q6_F3} | {Q6_F3.shown} | {Q6_F3==4} | |
E | Array (Increase/Same/Decrease) Radio-Buttons | Q7 | 1-7 | I,S,D | {Q7_4} | {Q7_4.shown} | {Q7_4=='D'} | |
: | Array (Multi Flexi) 1 To 10 | Q8 | ls1,todo,ls2 | min,max,avg | {Q8_ls1_max} | {Q8_ls2_avg.shown} | {Q8_ls2_min==7} | |
; | Array (Multi Flexi) Text | Q9 | hp,st,sw | 1st,2nd,3rd | {Q9_hp_3rd} | {Q9_hp_3rd.shown} | {Q9_hp_3rd=='Peter'} | |
C | Array (Yes/Uncertain/No) Radio-Buttons | Q10 | 1-5 | Y,N,U | {Q10_1} | {Q10_1.shown} | {Q10_3=='Y'} | |
X | Boilerplate Question | Q11 | {Q11.shown} | |||||
D | Date | Q12 | {Q12} | {Q12.shown} | ||||
* | Equation | Q13 | {Q13} | {Q13.shown} | {Q13>5} | |||
~124~ | File Upload (records number of files uploaded) | Q14 | {Q14} | {Q14>0} | ||||
G | Gender Drop-Down List | Q15 | M,F | {Q15} | {Q15.shown} | {Q15=='M'} | ||
U | Huge Free Text | Q16 | {Q16} | {Q16.shown} | {strlen(Q16)>100} | |||
I | Language Question | Q17 | {Q17} | {Q17.shown} | {Q17=='en'} | |||
! | List - Dropdown | Q18 | 1-5 | {Q18} | {Q18.shown} | {Q18==3} | ||
L | List Drop-Down/Radio-Button List | Q19 | A-Z | {Q19} | {Q19.shown} | {Q19=='X'} | ||
O | List With Comment Drop-Down/Radio-Button List + Textarea | Q20 | A-F | {Q20},{Q20comment} | {Q20.shown} | {Q20=='B'} | ||
T | Long Free Text | Q21 | {Q21} | {Q21.shown} | {strstr(Q21,'hello')>0} | |||
M | Multiple Choice Checkbox | Q22 | A-F, other | {Q22_E}, {Q22_other} | {Q22_E.shown}, {Q22_other.shown} | {Q22_E=='Y'} | ||
P | Multiple Choice With Comments Checkbox + Text | Q23 | A-F | {Q23_D}, {Q23_Dcomment} | {Q23_D.shown} | {!is_empty(Q23)} | ||
K | Multiple Numerical Question | Q24 | self,mom,dad | {Q24_self} | {Q24_self.shown} | {Q24_self>30} | ||
Q | Multiple Short Text | Q25 | A-F | {Q25_B} | {Q25_B.shown} | {substr(Q25_B,1,1)=='Q'} | ||
N | Numerical Question Type | Q26 | {Q26} | {Q26.shown} | {Q26 > 30} | |||
R | Ranking Style | Q27 | 1-4 | {Q27_1} | {Q27_1.shown} | {Q27_1==3} | ||
S | Short Free Text | Q28 | {Q28} | {Q28.shown} | {Q28=='mine'} | |||
Y | Yes/No Radio-Buttons | Q29 | {Q29} | {Q29.shown} | {Q29=='Y'} |
保留的'this','self'和'that'变量
通常,你希望评估问题的所有部分,例如计算已回答的子问题的数量,或总结得分。其他时候,你只想处理问题的某些行或列(例如获取行或列的总和并将它们存储在数据库中)。这些保留的变量使该过程相对无痛。
'this'变量专门用于“整体问题验证方程”和“子问题验证方程”高级问题选项中。它扩展为这些问题中每个单元格的变量名称。因此,如果要确保每个条目都大于3,则可以将“子问题验证方程式”设置为(this> 3)。
'self'和'that'变量更强大,并且用作在处理方程之前扩展的宏。语法选择是:
- self
- self.suffix
- self.sub-selector
- self.sub-selector.suffix
后缀是任何正常的qcode后缀(例如NAOK、value、shown)
子选择器是以下之一:
- 注释 - 只有作为注释的子项(例如来自带注释的多项选择和带注释的列表)
- 没有注释 - 只有不是注释的子项
- sq_X - 其中X是行或列标识符。仅选择与模式X匹配的子查询。请注意,搜索是在完整的代码标识符上完成的,然后sq_X匹配并包含子请求nX,X,Xn(例如,如果使用sq_1,则包含子参数a1,1a,1,11或001)。注意双尺度问题类型,其中子问题代码是QCODE_SQCODE_1和QCODE_SQCODE_1,以及排序问题类型,其中子问题代码是QCODE_1,QCODE_2 ....
示例:
- 是否已回答问题的任何部分?{count(self.NAOK)>0}
- 这个问题的评估分数是多少? {sum(self.value)}
你还可以使用它们来获取行和列总计。假设你有一组数字,其中包含AE行和第1-5列。
- 总计是多少? {sum(self.NAOK)}
- B行的总数是多少? {sum(self.sq_B.NAOK)}
- 第3列的总数是多少?{sum(self.sq_3.NAOK)}
'that'变量就像'self'变量,但是让你引用其他问题。它的语法是:
- that.qname
- that.qname.suffix
- that.qname.sub-selector
- that.qname.sub-selector.suffix
qname是没有任何子查询扩展名的问题名称。所以,假设您创建了一个问题'q1',那就是qname
示例:
- 是否已回答问题q1的任何部分? {count(that.q1.NAOK)>0}
- q2的评估分数是多少?{sum(that.q2.NAOK)}
- q3的总计是多少? {sum(that.q3.NAOK)}
- q4中C行的总数是多少? {sum(that.q4.sq_C.NAOK)}
- q4中第2列的总数是多少? {sum(that.q4.sq_2.NAOK)}
'self'和'that'变量可用于任何相关性、验证或定制。
需要注意的是,当你使用显示逻辑文件功能时,它将显示'self'和'that'的扩展值。这使你可以看到将生成的实际等式,以便你(和表达式管理器)可以验证变量是否存在。这可能看起来令人困惑,因为你可能会看到相当长的方程式。但是,如果你编辑问题,你将看到使用'self'和/或'that'的原始等式
另请注意,如果(a)要明确命名方程中使用的每个变量,或(b)使用没有子参数的变量(例如单个响应问题),则不应使用这些变量。在这些情况下,为变量添加'that'前缀是过度的,并且存在获得意外结果的风险。
NAOK的用法
NAOK -->“不适用”(NA)没问题(OK)
使用NAOK意味着所有或部分变量都是无关的(例如“不适用”(NA)是正常的(OK))。
当你在任何等式中放入一些来自问题的变量时:如果这个问题(或子问题)被条件隐藏:这将禁用所有等式。
例如:如果Q1的一个子问题被过滤,则count(Q1_SQ1,Q1_SQ2,Q1_SQ3,Q1_SQ4)总是给出一个空字符串。 要计算这个问题中检查的子问题的数量,可以count(Q1_SQ1.NAOK,Q1_SQ2.NAOK,Q1_SQ3.NAOK,Q1_SQ4.NAOK)。如果子问题被隐藏:表达式管理器返回一个空字符串。
没有NAOK:如果隐藏了一个问题或一个子问题:表达式管理器总是返回一个空字符串,同样返回false。
.shown总是使用NAOK系统(如果隐藏了空字符串),但是如果你需要答案的代码:在问题代码之后添加.NAOK总是一个好主意。除非你需要它并知道你做了什么。
另一个示例和信息在覆盖级联条件中提供
访问函数
表达式管理器提供对数学、字符串和用户定义函数的访问,如下所示。它具有这些函数的PHP和JavaScript等价物,因此它们在服务器端(PHP)和客户端(JavaScript)上的工作方式相同。添加新功能很容易。
已实现的函数
目前提供以下函数:
函数 | 含义 | 语法 |
---|---|---|
abs | 绝对值 | number abs(number) |
acos | 反余弦 | number acos(number) |
addslashes | Quote string with slashes | string addslashes(string) |
asin | 反正弦 | number asin(number) |
atan | 反正切 | number atan(number) |
atan2 | Arc tangent of two variables | number atan2(number, number) |
ceil | Round fractions up | number ceil(number) |
checkdate | Returns true(1) if it is a valid date in gregorian calendar | bool checkdate(month,day,year) |
convert_value | Convert a numerical value using a inputTable and outputTable of numerical values | number convert_value(fValue, iStrict, sTranslateFromList, sTranslateToList) |
cos | 余弦 | number cos(number) |
count | count the number of answered (non-blank)questions in the list | number count(arg1, arg12, ..., argN) |
countif | Count the number of answered questions in the list equal the first argument | number countif(matches, arg1, arg2, ... argN) |
countifop | Count the number of answered questions in the list which pass the criteria (arg op value) | number countifop(op, value, arg1, arg2, ... argN) |
date | 格式化本地日期/时间 | string date(format [, timestamp=time()]) |
exp | Calculates the exponent of e | number exp(number) |
fixnum | Display numbers with comma as radix separator, if needed | string fixnum(number) |
floor | Round fractions down | number floor(number) |
gmdate | 格式化GMT日期/时间 | string gmdate(format [, timestamp=time()]) |
html_entity_decode | Convert all HTML entities to their applicable characters (always uses ENT_QUOTES and UTF-8) | string html_entity_decode(string) |
htmlentities | Convert all applicable characters to HTML entities (always uses ENT_QUOTES and UTF-8) | string htmlentities(string) |
expr_mgr_htmlspecialchars | Convert special characters to HTML entities (always uses ENT_QUOTES and UTF-8) | string htmlspecialchars(string) |
expr_mgr_htmlspecialchars_decode | Convert special HTML entities back to characters (always uses ENT_QUOTES and UTF-8) | string htmlspecialchars_decode(string) |
idate | Format a local time/date as integer | string idate(string [, timestamp=time()]) |
if | Excel-style if(test,result_if_true,result_if_false) | if(test,result_if_true,result_if_false) |
implode | Join array elements with a string | string implode(glue,arg1,arg2,...,argN) |
intval | Get the integer value of a variable | int intval(number [, base=10]) |
is_empty | Determine whether a variable is considered to be empty | bool is_empty(var) |
is_float | Finds whether the type of a variable is float | bool is_float(var) |
is_int | Find whether the type of a variable is integer | bool is_int(var) |
is_nan | Finds whether a value is not a number | bool is_nan(var) |
is_null | Finds whether a variable is NULL | bool is_null(var) |
is_numeric | Finds whether a variable is a number or a numeric string | bool is_numeric(var) |
is_string | Find whether the type of a variable is string | bool is_string(var) |
join (New in 2.0 build 130129) | Join elements as a new string | join(arg1, arg2, ... argN) |
list | Return comma-separated list of non-blank values | string list(arg1, arg2, ... argN) |
log | The logarithm of number to base, if given, or the natural logarithm. | number log(number,base=e) |
ltrim | Strip whitespace (or other characters) from the beginning of a string | string ltrim(string [, charlist]) |
max | 寻找最大值 | number max(arg1, arg2, ... argN) |
min | 寻找最小值 | number min(arg1, arg2, ... argN) |
mktime | Get UNIX timestamp for a date (each of the 6 arguments are optional) | number mktime([hour [, minute [, second [, month [, day [, year ]]]]]]) |
modulo-function | The modulo function is not supported yet. You can use the floor() function instead | floor(x/y)==(x/y) |
nl2br | Inserts HTML line breaks before all newlines in a string | string nl2br(string) |
number_format | Format a number with grouped thousands | string number_format(number) |
pi | 获取pi的值 | number pi() |
pow | Exponential expression | number pow(base, exp) |
quoted_printable_decode | Convert a quoted-printable string to an 8 bit string | string quoted_printable_decode(string) |
quoted_printable_encode | Convert a 8 bit string to a quoted-printable string | string quoted_printable_encode(string) |
quotemeta | Quote meta characters | string quotemeta(string) |
rand | Generate a random integer, see this example | int rand() OR int rand(min, max) |
regexMatch | compare a string to a regular expression | bool regexMatch(pattern,input) |
round | Rounds a number to an optional precision | number round(val [, precision]) |
rtrim | Strip whitespace (or other characters) from the end of a string | string rtrim(string [, charlist]) |
sin | 正弦 | number sin(arg) |
sprintf | Return a formatted string | string sprintf(format, arg1, arg2, ... argN) |
sqrt | Square root | number sqrt(arg) |
stddev | Calculate the Sample Standard Deviation for the list of numbers | number stddev(arg1, arg2, ... argN) |
str_pad | Pad a string to a certain length with another string | string str_pad(input, pad_length [, pad_string]) |
str_repeat | 重复字符串 | string str_repeat(input, multiplier) |
str_replace | Replace all occurrences of the search string with the replacement string | string str_replace(search, replace, subject) |
strcasecmp | Binary safe case-insensitive string comparison | int strcasecmp(str1, str2) |
strcmp | Binary safe string comparison | int strcmp(str1, str2) |
strip_tags | Strip HTML and PHP tags from a string | string strip_tags(str, allowable_tags) |
stripos | Find position of first occurrence of a case-insensitive unicode string (starting by 0, return false if not found) | int stripos(haystack, needle [, offset=0]) |
stripslashes | Un-quotes a quoted string | string stripslashes(string) |
stristr | Case-insensitive strstr | string stristr(haystack, needle [, before_needle=false]) |
strlen | Get string length | int strlen(string) |
strpos | Find position of first occurrence of an unicode string (starting by 0, return false if not found) | int strpos(haystack, needle [ offset=0]) |
strrev | Reverse a string | string strrev(string) |
strstr | Find first occurrence of a string | string strstr(haystack, needle[, before_needle=false]) |
strtolower | Make a string lowercase | string strtolower(string) |
strtotime | Parse about any English textual datetime description into a Unix timestamp | int strtotime(string) |
strtoupper | Make a string uppercase | string strtoupper(string) |
substr | Return part of an unicode string | string substr(string, start [, length]) |
sum | Calculate the sum of values in an array | number sum(arg1, arg2, ... argN) |
sumifop | Sum the values of answered questions in the list which pass the criteria (arg op value) | number sumifop(op, value, arg1, arg2, ... argN) |
tan | 正切 | number tan(arg) |
time | Return current UNIX timestamp | number time() |
trim | Strip whitespace (or other characters) from the beginning and end of a string | string trim(string [, charlist]) |
ucwords | Uppercase the first character of each word in a string | string ucwords(string) |
unique | Returns true if all non-empty responses are unique | boolean unique(arg1, ..., argN) |
计划或被考虑的函数
计划(或正在考虑)但尚未实施的其他函数包括以下内容。其中一些是为了与另一个调查工具向后兼容。
语法 | 含义 | 注释 |
---|---|---|
e() | 返回e的值 | |
formatDate(X,PAT) | 返回根据Java数据格式模式格式化的日期X的字符串值 | |
formatNumber(X,PAT) | 返回根据Java编号格式化的数字X的字符串值格式模式PAT | |
getAnsOption(X) | 返回与所选选项对应的文本对应答案X | 这与X.shown相同 |
返回与节点X的索引Y处的选项对应的文本 | ||
getRelevance(X) | 返回问题X的相关方程式 | |
getStartTime() | 返回与访问开始时的系统时间对应的日期 | |
getType(X) | 返回数据类型的字符串名称 - 例如*NA* if isNA() | |
gotoFirst() | 跳转到第一组相关问题 - 这违反了系统的正常流程 | |
gotoNext() | 跳转到下一组相关问题 - 这违反了系统的正常流程 | |
gotoPrevious() | 跳转到上一组相关问题 - 这违反了系统的正常流程 | |
isAsked(X) | 如果答案既不是*NA*、*INVALID*,也不是*UNASKED* ,则返回true | |
isInvalid(X) | 如果答案类型为*INVALID*,则返回true | |
isNA(X) | 如果答案类型为*NA* ,则返回true | |
isNotUnderstood(X) | 如果答案类型为*HUH* ,则返回true | |
isRefused(X) | 如果答案类型为*REFUSED* ,则返回true | |
isSpecial(X) | 如果答案类型为 *UNASKED*、 *NA*、 *REFUSED*,、*INVALID*、 *UNKNOWN*或*HUH*,则返回true | |
isUnknown(X) | 如果答案类型为*UNKNOWN* ,则返回true | |
jumpTo(X) | 跳转到包含指定问题的组 - 这违反了系统的正常流程 | |
jumpToFirstUnasked() | 跳转到第一个未解决的问题 |
|
lastIndexOf(X,Y) | 返回字符串X中字符串Y的最后一个索引(基数为0)。如果Y中不包含Y,则返回-1 | |
list(X,...) | 一个包含逗号分隔的正值列表的字符串,其中"和"分隔最后两个 | |
mean(X,...) | 返回值列表的平均值 | |
numAnsOptions(X) | 返回问题X的答案选项的数量 | |
orlist(X,...) | 包含的字符串逗号分隔的正值列表,用"或"分隔最后两个 | |
parseDate(X,PAT) | 返回用Java日期格式模式PAT解析的字符串X的日期值 | |
parseNumber(X,PAT) | 返回用Java数字格式模式PAT | |
showAllResponsesExcept( questionList,attributeList,attributeTitleList) | questionList =以管道分隔的问题标识符列表; attributeList =管道分隔的属性列表(如问题#,标题,文本,类型 - 因此您可以决定要显示的内容); attributeTitleList =管道分隔的表头列表,因此可以使报告国际化。 | |
showTheseResponses( questionList,attributeList,attributeTitleList) | questionList =管道分隔的问题标识符列表; attributeList =管道分隔的属性列表(如问题#,标题,文本,类型 - 因此您可以决定要显示的内容); attributeTitleList =管道分隔的表头列表,因此可以使报告国际化。 |
表达式管理器知道哪些变量是本地的
为了正确构建页面JavaScript,表达式管理器需要知道页面上设置了哪些变量,以及它们的JavaScript ID是什么(例如,对于document.getElementById(x))。它还必须知道在其他页面上设置了哪些变量(以便它可以确保所需的变量<input type='hidden' value='x'> 字段存在并填充)。
级联条件
如果任何变量不相关,则整个等式将是无关紧要的(假)。例如,在下表中,N / A表示其中一个变量不相关
操作符 | 示例 | a | b | 结果 |
---|---|---|---|---|
+ (unary) | +a | N/A | false | |
! | !a | N/A | false | |
== (or eq) | a == b | N/A | 5 | false |
== (or eq) | a == b | N/A | 0 | false |
== (or eq) | a == b | N/A | N/A | false |
!= (or ne) | a != b | N/A | 5 | false |
!= (or ne) | a != b | N/A | N/A | false |
!= (or ne) | a != b | N/A | 0 | false |
> (or gt) | a > b | N/A | 5 | false |
>= (or ge) | a >= b | N/A | 5 | false |
< (or lt) | a < b | N/A | 5 | false |
<= (or le) | a <= b | N/A | 5 | false |
and | a and b | N/A | 5 | false |
and | a and b | N/A | N/A | false |
or | a or b | N/A | N/A | false |
or | a or b | N/A | 5 | false |
+ | a + b | N/A | 5 | false |
* | a * b | N/A | 5 | false |
/ | a / b | 5 | N/A | false |
() | (a) | N/A | false | |
(exp) | (a && b) | N/A | 5 | false |
(exp) op (exp) | (b + b) > (a && b) | N/A | 5 | false |
function | sum(a,b,b) | N/A | 5 | false |
function | max(a,b) | N/A | 5 | false |
function | min(a,b) | N/A | 5 | false |
function | implode(', ',a,b,a,b) | N/A | 5 | false |
function | if(a,a,b) | N/A | 5 | false |
function | is_empty(a) | N/A | false | |
function | is_empty(a) | 0 (or blank) | true | |
function | !is_empty(a) | N/A | false |
重写级联条件
假设你要显示所有相关答案的总计。您可以尝试使用等式 {sum(q1,q2,q3,...,qN)}。然而,这被内部转译为LEMif(LEManyNA('q1','q2','q3',...,'qN'),,sum(LEMval('q1'),LEMval('q2'),LEMval('q3'),...,LEMval('qN')))。因此,如果任何值q1-qN不相关,则等式将始终返回false。在这种情况下,sum()将显示0,直到所有问题都得到回答。
为了解决这个问题,每个变量都可以添加一个“.NAOK”后缀(意思是“不适用”)。在这种情况下,会发生以下行为。假设你有一个变量q1.NAOK
- q1没有添加到LEManyNA()子句中
- LEMval('q1')将继续检查响应是否相关,并将返回 “” 如果不是(因此个别不相关的反应将被忽略,但它们不会使整个表达无效)。
因此,运行总问题的解决方案是使用方程式sum(q1.NAOK,q2.NAOK,q3.NAOK,...,qN.NAOK)。
使用.NAOK后缀还可以让作者设计具有多种可能路径的调查,然后在以后汇聚到公共路径上。例如,受试者以一种超出正常反应范围的方式回答调查。作者可以提醒受试者他们可能无法获得有效结果,并询问他们是否真的想继续进行调查。如果他们说“是”,则会显示其余问题。 “其余问题”的条件将检查初始回答是否在正常范围内得到回答,或者受试者是否对只有在正常范围之外回答的相关问题说“是”。
表达式管理器如何支持条件微裁剪?
以下是微裁剪的示例(其中问题类型=='expr'表示公式):
问题代码 | 相关性 | 问题类型 | 问题 |
---|---|---|---|
name | 1 | text | 你叫什么名字? |
age | 1 | text | 你多大了? |
badage | !is_empty(age) | expr | {(age<16) or (age>80)} |
agestop | badage | message | 对不起,{name}, 对这个测试而言,你太{if( (age<16),'年轻',if( (age>80),'老','middle-aged') ) } 了。 |
kids | !badage | yesno | 你有孩子吗? |
parents | 1 | expr | {!badage && kids=='Y'} |
numKids | parents | text | 你有几个孩子? |
kid1 | parents && numKids >= 1 | text | 你的第一个孩子多大了? |
kid2 | parents && numKids >= 2 | text | 你的第二个孩子多大了? |
kid3 | parents && numKids >= 3 | text | 你的第三个孩子多大了? |
kid4 | parents && numKids >= 4 | text | 你的第四个孩子多大了? |
kid5 | parents && numKids >= 5 | text | 你的第五个孩子多大了? |
sumage | 1 | expr | {sum(kid1.NAOK,kid2.NAOK,kid3.NAOK,kid4.NAOK,kid5.NAOK)} |
report | parents | yesno | {name},你现在{age} 岁,并且有{numKids}个孩子. The sum of ages of your first {min(numKids,5)} kids is {sumage} |
所有这些问题都可以在一个页面上(例如在同一组中),并且只显示相关问题。此外,当你输入子项的年龄时,最后一个问题中的sum()表达式将在页面上动态更新。
表达式管理器通过使用named包围每个表达式来提供此功能<span> 元素。每次值更改时,它都会重新计算应该出现的表达式 <span> 元素并重新生成显示。你可以在同一页面上拥有数十个甚至数百个这样的定制表达式,并且页面将在单个屏幕刷新中重新显示所有这些表达式。
将LimeSurvey 1.91+映射到表达式管理器功能
Old Feature | New Feature | Comments |
---|---|---|
条件 | 条件 | 你可以使用非常复杂的条件方程式,并访问更广泛的变量 |
评估 | 方程式 | 任何评估分数都可以重新组织成方程式。这既可以确保将分数写入数据库,也可以让你看到当前页面上分数值的动态变化 |
替换 | 表达式管理器 | 核心引擎获取输入字符串并将花括号中的所有内容视为表达式 - 因此它处理所有历史替换类型。为了避免搞乱嵌入式JavaScript,表达式管理器只处理花括号之间的内容,只要(a)花括号内没有前导空格或尾随空格 - 例如{expr}是表达式,但{expr},{expr},和{expr}不是表达式。此外,Expression Manager不会在其自己的字符串中处理内容(例如{list('hi','there {braces}')}生成“hi there {braces}”)。它也忽略了转义的花括号(例如\ {这不是表达式\}) |
验证 | 表达式管理器 | 计划是采用当前的最小/最大问题属性并拥有表达式管理器处理它们。这样,最小/最大值可以是表达式本身 |
语法突出显示
为了帮助输入和验证表达式,EM提供了语法突出显示功能,具有以下功能:
语法突出显示的类型和含义
颜色 | 实例 | 含义 | 工具提示 | 注释 |
---|---|---|---|---|
棕褐色背景 | Sample | 整个方程式 | none | 花括号中被识别为方程式的任何东西(例如,没有前导或尾随空白)将用棕褐色背景进行颜色编码,以帮助将其与周围文本区分开来 |
粗体红色文本 | Sample | 错误 | 关于错误的一些解释 | 可以是一个未知变量或函数中的错误,……调查可以被完全破坏,所以不要向公众用户展示。 |
蓝色文本 | Sample | 函数名称 | 含义和允许语法 | 函数名称,或者应该是函数的东西,因为它们后跟一个左括号,以粗体蓝色文本显示。工具提示显示函数的含义和允许的语法。 |
灰色文本 | Sample | 字符串 | none | 单引号和双引号字符串以灰色文本显示 |
青色文本 | Sample | variable set on the same page, | [name or SGQA code]: question; value; answerList showing codes for each value | Any variable that is set on the same page to the current question is shown in cyan text, showning it can be updated in javascript. The tooltip shows its name (if you used INSERTANS:xxx) or SGQA code (if you used the new naming system), the actual question, and its current value (or blank if not set). If the question type expects responses from an enumerated value set, the mapping of the codes to display values is show. |
green text | Sample | variable set on a prior page | [name or SGQA code]: question; value; answerList showing codes for each value | Any variable that is set on a prior page is shown in bold green text. The tooltip shows its name (if you used INSERTANS:xxx) or SGQA code (if you used the new naming system), the actual question, and its current value (or blank if not set). If the question type expects responses from an enumerated value set, the mapping of the codes to display values is show. |
bold pink text | Sample | variable set on a later page in general : empty at survey start, but can be filled with index or move previous | [name or SGQA code]: question; value; answerList showing codes for each value | Any variable that is set on a prior page is shown in bold pink text. The tooltip shows its name (if you used INSERTANS:xxx) or SGQA code (if you used the new naming system), the actual question, and its current value (or blank if not set). If the question type expects responses from an enumerated value set, the mapping of the codes to display values is show. |
bold tan text | Sample | a lime replacement value | the value | Lime Replacement Strings (like {TOKEN:xxx}, {PRIVACY_MESSAGE}) are shown in bold tan text. |
red text | Sample | assignment operator (=) | warning message | If you use one of the assignment operator (=) that operator will be displayed in red text. This is meant to help prevent accidental re-assignment of values when you really meant to check whether a == b instead of setting the value of a = b. |
normal black text | Sample | punctuation | none | All other punctuation within the expression is shown as normal black text. |
red-boxed text | a bold red line surrounds the error | syntax error | description of the error | Any detected syntax errors are shown by surrounding the error with a red box. The tooltip shows the error. Examples include unmatched parentheses, use of undefined functions, passing the wrong number of arguments to functions, poorly structured expressions (e.g. missing operators between variables), trying to assign a new value to a read-only variable, trying to assign values to non-variables, or using unsupported syntax. Note that the syntax error dectection system may only report one error in an expression even if there are multiple errors; however, if any errors are detected, at least one error will be shown. |