11. 表达式、筛选和计算值

提示

如果您在pyqgis控制台之外,则此页面上的代码片段需要以下导入:

 1from qgis.core import (
 2    edit,
 3    QgsExpression,
 4    QgsExpressionContext,
 5    QgsFeature,
 6    QgsFeatureRequest,
 7    QgsField,
 8    QgsFields,
 9    QgsVectorLayer,
10    QgsPointXY,
11    QgsGeometry,
12    QgsProject,
13    QgsExpressionContextUtils
14)

QGIS对类SQL表达式的解析提供了一些支持。只支持一小部分SQL语法。可以将表达式计算为布尔谓词(返回 TrueFalse )或作为函数(返回标量值)。看见 表达式 有关可用功能的完整列表,请参阅用户手册。

支持三种基本类型:

  • 数字-既包括整数,也包括小数。 1233.14

  • 字符串-它们必须用单引号引起来: 'hello world'

  • 列引用-求值时,引用将替换为字段的实际值。这些名字并没有被转义。

以下操作可用:

  • 算术运算符: +, -, *, /, `` ^``

  • 圆括号:用于强制运算符优先: (1 + 1) * 3

  • 一元加和减: -12+5

  • 数学函数: sqrtsincostanasinacosatan

  • 转换函数: to_intto_realto_stringto_date

  • 几何体函数: $area$length

  • 几何图形处理函数: $x$y$geometrynum_geometriescentroid

并且支持以下谓词:

  • 比较: =!=>>=<<=

  • 模式匹配: LIKE (使用%和_), ~ (正则表达式)

  • 逻辑谓词: ANDORNOT

  • 空值检查: IS NULLIS NOT NULL

谓词示例:

  • 1 + 2 = 3

  • sin(angle) > 0

  • 'Hello' LIKE 'He%'

  • (x > 10 AND y > 10) OR z = 0

标量表达式示例:

  • 2 ^ 10

  • sqrt(val)

  • $length + 1

11.1. 解析表达式

以下示例显示如何检查给定表达式是否可以正确解析:

1exp = QgsExpression('1 + 1 = 2')
2assert(not exp.hasParserError())
3
4exp = QgsExpression('1 + 1 = ')
5assert(exp.hasParserError())
6
7assert(exp.parserErrorString() == '\nsyntax error, unexpected end of file')

11.2. 计算表达式

表达式可以在不同的上下文中使用,例如用于过滤要素或计算新的字段值。在任何情况下,都必须对表达式求值。这意味着它的值是通过执行指定的计算步骤来计算的,计算步骤可以是简单的算术运算,也可以是聚合表达式。

11.2.1. 基本表达式

此基本表达式计算一个简单的算术运算:

exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())
<QgsExpression: '2 * 3'>
6

表达式也可用于比较,计算结果为1 (True )或0 (False )

exp = QgsExpression('1 + 1 = 2')
exp.evaluate()
# 1

11.2.2. 带有功能的表达式

若要针对要素计算表达式,请使用 QgsExpressionContext 必须创建对象并将其传递给EVALUATE函数,才能允许表达式访问特征的字段值。

以下示例显示如何使用名为“Column”的字段创建特征,以及如何将该特征添加到表达式上下文中。

 1fields = QgsFields()
 2field = QgsField('Column')
 3fields.append(field)
 4feature = QgsFeature()
 5feature.setFields(fields)
 6feature.setAttribute(0, 99)
 7
 8exp = QgsExpression('"Column"')
 9context = QgsExpressionContext()
10context.setFeature(feature)
11exp.evaluate(context)
12# 99

下面是一个更完整的示例,说明如何在向量层的上下文中使用表达式来计算新的字段值:

 1from qgis.PyQt.QtCore import QVariant
 2
 3# create a vector layer
 4vl = QgsVectorLayer("Point", "Companies", "memory")
 5pr = vl.dataProvider()
 6pr.addAttributes([QgsField("Name", QVariant.String),
 7                  QgsField("Employees",  QVariant.Int),
 8                  QgsField("Revenue", QVariant.Double),
 9                  QgsField("Rev. per employee", QVariant.Double),
10                  QgsField("Sum", QVariant.Double),
11                  QgsField("Fun", QVariant.Double)])
12vl.updateFields()
13
14# add data to the first three fields
15my_data = [
16    {'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1},
17    {'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5},
18    {'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}]
19
20for rec in my_data:
21    f = QgsFeature()
22    pt = QgsPointXY(rec['x'], rec['y'])
23    f.setGeometry(QgsGeometry.fromPointXY(pt))
24    f.setAttributes([rec['name'], rec['emp'], rec['rev']])
25    pr.addFeature(f)
26
27vl.updateExtents()
28QgsProject.instance().addMapLayer(vl)
29
30# The first expression computes the revenue per employee.
31# The second one computes the sum of all revenue values in the layer.
32# The final third expression doesn’t really make sense but illustrates
33# the fact that we can use a wide range of expression functions, such
34# as area and buffer in our expressions:
35expression1 = QgsExpression('"Revenue"/"Employees"')
36expression2 = QgsExpression('sum("Revenue")')
37expression3 = QgsExpression('area(buffer($geometry,"Employees"))')
38
39# QgsExpressionContextUtils.globalProjectLayerScopes() is a convenience
40# function that adds the global, project, and layer scopes all at once.
41# Alternatively, those scopes can also be added manually. In any case,
42# it is important to always go from “most generic” to “most specific”
43# scope, i.e. from global to project to layer
44context = QgsExpressionContext()
45context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(vl))
46
47with edit(vl):
48    for f in vl.getFeatures():
49        context.setFeature(f)
50        f['Rev. per employee'] = expression1.evaluate(context)
51        f['Sum'] = expression2.evaluate(context)
52        f['Fun'] = expression3.evaluate(context)
53        vl.updateFeature(f)
54
55print(f['Sum'])
876.5

11.2.3. 使用表达式筛选层

以下示例可用于过滤一个层并返回与谓词匹配的任何要素。

 1layer = QgsVectorLayer("Point?field=Test:integer",
 2                           "addfeat", "memory")
 3
 4layer.startEditing()
 5
 6for i in range(10):
 7    feature = QgsFeature()
 8    feature.setAttributes([i])
 9    assert(layer.addFeature(feature))
10layer.commitChanges()
11
12expression = 'Test >= 3'
13request = QgsFeatureRequest().setFilterExpression(expression)
14
15matches = 0
16for f in layer.getFeatures(request):
17   matches += 1
18
19print(matches)
7

11.3. 处理表达式错误

在表达式分析或计算过程中可能会发生与表达式相关的错误:

1exp = QgsExpression("1 + 1 = 2")
2if exp.hasParserError():
3   raise Exception(exp.parserErrorString())
4
5value = exp.evaluate()
6if exp.hasEvalError():
7   raise ValueError(exp.evalErrorString())