regex - 从postgresql中的字符串转换方程

标签 regex string postgresql equation

我正在尝试编写一个接受字符串的查询,其中一个方程式

x^3 + 0.0046x^2 - 0.159x +1.713

是预期的。该等式用于根据现有值列表计算输出表中的新值。因此,我需要将输入的方程式字符串转换为 postgresql 可以处理的方程式,例如

power(data.value,3) + 0.0046 * power(data.value,2) - 0.159 * data.value + 1.713

此任务中的一些令人欣慰的约束是

  1. 方程将始终采用多项式形式,例如总和(A_n * x^n)
  2. 用户将始终使用'x'来表示输入方程中的变量

我一直在将我的查询推送到一个字符串中并在最后执行它,例如

_query TEXT;
SELECT 'select * from ' INTO _query;
SELECT _query || 'product.getlength( ' || min || ',' || max || ')' INTO _query;
RETURN QUERY EXECUTE _query;

因此我知道我只需要以某种方式

  1. 将“x”替换为“data.values”
  2. 找到等式字符串中所有包含数字的地方 紧接在“x”之前,并添加一个“*”
  3. 找出方程字符串中的所有指数运算 (x^n) 和 将它们转换为幂(x,n)

这对很多人来说可能是非常微不足道的事情,不幸的是 postgresql 不是我最好的技能,我已经花费了更多的时间来完成这项工作。非常感谢任何类型的帮助,干杯。

最佳答案

您的上午 9 点到中午的时间范围已经结束,但现在开始。

多项式的每一项都有 4 个元素:

  1. 加减修饰符
  2. 乘数
  3. 参数,在你的情况下总是x
  4. 权力

问题是这些元素并不总是存在。第一项没有加法元素,尽管它可以有一个减法符号 - 然后通常连接到乘数。乘数仅在不等于 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;

SQLFiddle

这假设您有一个要加入的 id 列。如果您只有一个 value,那么您仍然可以这样做,但您应该将上述查询包装在一个函数中,该函数提供多项式和值。假定幂是整数,但您可以通过在正则表达式中添加点 .::float 转换而不是 轻松地将其转换为实数>::intCASE 语句中。您还可以通过将另一个捕获组添加到正则表达式和查询中的 case 语句来支持负幂,与乘数项相同;我把这个留给你下个周末的 hackfest。

此查询还将处理“奇数”多项式,例如 -4.3x^3+ 101.2 + 0.0046x^6 - 0.952x^7 +4x 只要保持上述模式.

关于regex - 从postgresql中的字符串转换方程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36993523/

相关文章:

ruby-on-rails - 如何将 Heroku PG 转储导入本地机器

sql - 如何在 oracle 中拆分以空格分隔的字符串并将每个单词添加到 Oracle 11g 中的不同行?

php - 多行单引号字符串

c++ - 从字符串中删除两个字符以获得唯一字符的可能性

sql - 如何使用MATLAB和JDBC加快表检索的速度?

spring - 无法使用 JPA 截断 PostgreSQL 表

python - python/jinja 中的正则表达式模式替换

Mysql将列值视为选择的正则表达式

python - 正则表达式在 python 中匹配和清理引号

java - 在Java字符串中,如何仅用1行代码剪切字符串的一部分(可能使用正则表达式)?