从postgresql中的字符串转换方程式
Convert equation from string in postgresql
我正在尝试编写一个接受字符串的查询,其中方程的形式为
x^3 + 0.0046x^2 - 0.159x +1.713
符合预期。该等式用于根据现有值列表计算输出 table 中的新值。因此,我需要将输入的方程式字符串转换为 postgresql 可以处理的方程式,例如
power(data.value,3) + 0.0046 * power(data.value,2) - 0.159 * data.value + 1.713
此任务中的一些令人欣慰的约束是
- 方程将始终采用多项式形式,例如总和(A_n * x^n)
- 用户将始终使用'x'来表示输入方程中的变量
我一直在将我的查询推送到一个字符串中并在最后执行它,例如
_query TEXT;
SELECT 'select * from ' INTO _query;
SELECT _query || 'product.getlength( ' || min || ',' || max || ')' INTO _query;
RETURN QUERY EXECUTE _query;
因此我知道我只需要以某种方式
- 将 'x' 替换为 'data.values'
- 找出等式字符串中所有包含数字的地方
紧接在 'x' 之前,并添加一个 '*'
- 找到方程字符串中的所有指数运算 (x^n) 和
将它们转换为 power(x,n)
这对很多人来说可能是非常微不足道的事情,不幸的是 postgresql 不是我最好的技能,我已经花费了更多的时间来完成这项工作。非常感谢任何类型的帮助,干杯。
您的上午 9 点到中午的时间范围已经结束,但现在开始了。
多项式的每一项都有4个元素:
- Addition/subtraction修饰符
- 乘数
- 参数,在你的情况下总是
x
- 功率
问题是这些元素并不总是存在。第一项没有加法元素,尽管它可以有一个减法符号 -
然后通常连接到乘法器。乘数仅在不等于 1 时给出。最后一项中不存在参数,最后两项中也没有幂。
在正则表达式解析中使用可选的捕获组,您可以解决这个问题,而 PostgreSQL 对此有方便的 regexp_matches()
function:
SELECT * FROM
regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms);
正则表达式是这样说的:
\s*
读取0个或多个空格。
([+-]?)
捕获 0 或 1 个加号或减号。
\s*
读取0个或多个空格。
([0-9.]*)
捕获一个由数字和小数点组成的数字(如果存在)。
(x?)
捕获参数x
。这是区分最后两个术语所必需的,请参阅下面的查询。
\^?
读取电源符号(如果存在)。必须转义,因为 ^
是约束字符。
([0-9]*)
捕获整数(如果存在)。
g
修饰符对字符串中的每个匹配模式重复此过程。
在你的字符串上,这会以字符串数组的形式产生:
| terms |
|-----------------|
| {'','',x,3} |
| {+,0.0046,x,2} |
| {-,0.159,x,''} |
| {+,1.713,'',''} |
| {'','','',''} |
(我不知道为什么最后一行全是空字符串。也许真正的专家可以解释一下。)
根据这个结果,您可以将查询拼凑起来:
SELECT id, sum(term)
FROM (
SELECT id,
CASE WHEN terms[1] = '-' THEN -1
WHEN terms[1] = '+' THEN 1
WHEN terms[3] = 'x' THEN 1 -- If no x then NULL
END *
CASE terms[2] WHEN '' THEN 1. ELSE terms[2]::float
END *
value ^ CASE WHEN terms[3] = '' THEN 0 -- If no x then 0 (x^0)
WHEN terms[4] = '' THEN 1 -- If no power then 1 (x^1)
ELSE terms[4]::int
END AS term
FROM data
JOIN regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms) ON true
) sub
GROUP BY id
ORDER BY id;
这假设您有一个要加入的 id
列。如果你只有一个 value
那么你仍然可以这样做,但你应该将上面的查询包装在一个你提供多项式和值的函数中。假定幂是整数,但您可以通过在正则表达式中添加一个点 .
并在 [=31 中添加一个 ::float
而不是 ::int
来轻松地将其转换为实数=] 语句。您还可以通过将另一个捕获组添加到正则表达式和查询中的 case 语句来支持负幂,与乘数项相同;我把这个留给你下周末的 hackfest。
只要保持上述模式,此查询还将处理 "odd" 多项式,例如 -4.3x^3+ 101.2 + 0.0046x^6 - 0.952x^7 +4x
。
我正在尝试编写一个接受字符串的查询,其中方程的形式为
x^3 + 0.0046x^2 - 0.159x +1.713
符合预期。该等式用于根据现有值列表计算输出 table 中的新值。因此,我需要将输入的方程式字符串转换为 postgresql 可以处理的方程式,例如
power(data.value,3) + 0.0046 * power(data.value,2) - 0.159 * data.value + 1.713
此任务中的一些令人欣慰的约束是
- 方程将始终采用多项式形式,例如总和(A_n * x^n)
- 用户将始终使用'x'来表示输入方程中的变量
我一直在将我的查询推送到一个字符串中并在最后执行它,例如
_query TEXT;
SELECT 'select * from ' INTO _query;
SELECT _query || 'product.getlength( ' || min || ',' || max || ')' INTO _query;
RETURN QUERY EXECUTE _query;
因此我知道我只需要以某种方式
- 将 'x' 替换为 'data.values'
- 找出等式字符串中所有包含数字的地方 紧接在 'x' 之前,并添加一个 '*'
- 找到方程字符串中的所有指数运算 (x^n) 和 将它们转换为 power(x,n)
这对很多人来说可能是非常微不足道的事情,不幸的是 postgresql 不是我最好的技能,我已经花费了更多的时间来完成这项工作。非常感谢任何类型的帮助,干杯。
您的上午 9 点到中午的时间范围已经结束,但现在开始了。
多项式的每一项都有4个元素:
- Addition/subtraction修饰符
- 乘数
- 参数,在你的情况下总是
x
- 功率
问题是这些元素并不总是存在。第一项没有加法元素,尽管它可以有一个减法符号 -
然后通常连接到乘法器。乘数仅在不等于 1 时给出。最后一项中不存在参数,最后两项中也没有幂。
在正则表达式解析中使用可选的捕获组,您可以解决这个问题,而 PostgreSQL 对此有方便的 regexp_matches()
function:
SELECT * FROM
regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms);
正则表达式是这样说的:
\s*
读取0个或多个空格。([+-]?)
捕获 0 或 1 个加号或减号。\s*
读取0个或多个空格。([0-9.]*)
捕获一个由数字和小数点组成的数字(如果存在)。(x?)
捕获参数x
。这是区分最后两个术语所必需的,请参阅下面的查询。\^?
读取电源符号(如果存在)。必须转义,因为^
是约束字符。([0-9]*)
捕获整数(如果存在)。
g
修饰符对字符串中的每个匹配模式重复此过程。
在你的字符串上,这会以字符串数组的形式产生:
| terms |
|-----------------|
| {'','',x,3} |
| {+,0.0046,x,2} |
| {-,0.159,x,''} |
| {+,1.713,'',''} |
| {'','','',''} |
(我不知道为什么最后一行全是空字符串。也许真正的专家可以解释一下。)
根据这个结果,您可以将查询拼凑起来:
SELECT id, sum(term)
FROM (
SELECT id,
CASE WHEN terms[1] = '-' THEN -1
WHEN terms[1] = '+' THEN 1
WHEN terms[3] = 'x' THEN 1 -- If no x then NULL
END *
CASE terms[2] WHEN '' THEN 1. ELSE terms[2]::float
END *
value ^ CASE WHEN terms[3] = '' THEN 0 -- If no x then 0 (x^0)
WHEN terms[4] = '' THEN 1 -- If no power then 1 (x^1)
ELSE terms[4]::int
END AS term
FROM data
JOIN regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms) ON true
) sub
GROUP BY id
ORDER BY id;
这假设您有一个要加入的 id
列。如果你只有一个 value
那么你仍然可以这样做,但你应该将上面的查询包装在一个你提供多项式和值的函数中。假定幂是整数,但您可以通过在正则表达式中添加一个点 .
并在 [=31 中添加一个 ::float
而不是 ::int
来轻松地将其转换为实数=] 语句。您还可以通过将另一个捕获组添加到正则表达式和查询中的 case 语句来支持负幂,与乘数项相同;我把这个留给你下周末的 hackfest。
只要保持上述模式,此查询还将处理 "odd" 多项式,例如 -4.3x^3+ 101.2 + 0.0046x^6 - 0.952x^7 +4x
。