Java - 使用正则表达式解析具有复数系数的多项式
Java - parsing a polynomial with complex coefficients with regex
作为计算方阵 Jordan 范式的个人项目的一部分,我发现我需要解析具有复系数的多项式以简化大量代码。
(相关代码在post底部)
我要解析的多项式具有以下形式:
- 系数可以是实数、虚数或复数。
- 如果系数是复数,它会用括号括起来。如果这些括号是前导系数,则它们前面不会有
+
或 -
。
- 如果系数是实部、虚部或复数,其实部 and\or 虚部的大小为 1,则
1
不会出现,只会出现符号。
- 括号前只能有
+
。
- 变量
x
可能有一个幂 (>2
),可能有一个幂 1 然后它显示为 x
,或者可能根本不出现。
- 关于多项式的文本表示没有更多规则,即幂不一定按 ascending\descending 顺序排列。
一些格式正确的多项式示例:
1
-1
-2.1x
3i
x^2-1
-x^3+2x+1
(5-5i)x^2-x-1
(-1+i)x-5
-ix^3-x^2+1
..还有一些格式错误的:
1x
(不必要的领先1
)
+(+1-2i)x
(括号有前导+
,实部有前导+
)
(5.1i)x^2
(不需要括号,因为系数是虚数)
-(i-1)
(复数系数有前导-
)
在网上阅读了一些内容(SO,Java 教程,Java API)后,我很快得出结论,正则表达式将是最简单的解析方法,考虑到所有上述限制。
在正式方面,这个任务的正则表达式是可能的,因为我画了一个 NFA,它只接受这样的有效表达式。
我正在做这个 TDD(通过 JUnit 4),但这个测试失败了:
assertEquals("Polynomial parsed incorrectly.", poly07, PolyParser.parse(exp07));
其中 poly07
看起来像这样:(5-5i)x^2-x-1
.
这是正在引发的异常:
java.lang.NumberFormatException: For input string: "5-5"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at PolyParser.parse(PolyParser.java:55)
at PolyParserTest.testParse(PolyParserTest.java:59)
我试过调试,发现正则表达式捕获了 5-5i
(后来去掉了 i
)。然后它尝试使用参数字符串 5-5
调用 Double.parseDouble
,这会导致异常。
读完所有内容后,我不太明白需要对正则表达式进行哪些调整才能使整个节目正常运行。
此外,正则表达式的排序不像上面提到的表示约束那样,因为我想在尝试将其解析为真实系数之前查看系数是否复杂;还遇到了实数(即带小数点)被解析为整数的问题,所以正则表达式首先处理实数。
正则表达式:
public static final String POLYNOMIAL_REGEX =
"([+-])?" + // leading plus or minus
"(\()?" + // parenthesis to denote the beginning of a complex number
"([+-])?(((\d+.\d+)|\d+)i)?" + // component of coefficient, imaginary
"(((-)?\d+.\d+)|\d+)?" + // component of coefficient, real
"(\))?" + // parenthesis to denote the end of a complex number
"(x)?" + // variable
"(?:\^(\d+))?"; // power of the variable
我不会在此处 post 所有相关代码,因为它会使内容混乱。所有代码都在 GitHub 上,只需确保切换到分支 PolyParser
.
相关代码在文件中:
PolyParser.java
Polynomial.java
Complex.java
测试单元在文件PolyParserTest.java
.
中
正则表达式基本上无法解析表达式,因为它们无法跟踪嵌套(例如括号)。这是大多数人不知道的一课,他们是通过艰难的方式发现的。
但是,表达式很容易解析,使用自上而下的解析。请参阅我关于如何执行此操作的回答:此答案涵盖了如何进行解析,并链接到另一个讨论如何构建 AST 来表示您的表达式的答案。
第一步:编写一个语法来表示您的表达式允许的内容。您的问题中有一个特别的描述,但是语法会迫使您准确地写出合法的内容和不合法的内容。使用该语法,您可以非常轻松地编写上面建议的递归下降解析器。
作为计算方阵 Jordan 范式的个人项目的一部分,我发现我需要解析具有复系数的多项式以简化大量代码。
(相关代码在post底部)
我要解析的多项式具有以下形式:
- 系数可以是实数、虚数或复数。
- 如果系数是复数,它会用括号括起来。如果这些括号是前导系数,则它们前面不会有
+
或-
。 - 如果系数是实部、虚部或复数,其实部 and\or 虚部的大小为 1,则
1
不会出现,只会出现符号。 - 括号前只能有
+
。 - 变量
x
可能有一个幂 (>2
),可能有一个幂 1 然后它显示为x
,或者可能根本不出现。 - 关于多项式的文本表示没有更多规则,即幂不一定按 ascending\descending 顺序排列。
一些格式正确的多项式示例:
1
-1
-2.1x
3i
x^2-1
-x^3+2x+1
(5-5i)x^2-x-1
(-1+i)x-5
-ix^3-x^2+1
..还有一些格式错误的:
1x
(不必要的领先1
)+(+1-2i)x
(括号有前导+
,实部有前导+
)(5.1i)x^2
(不需要括号,因为系数是虚数)-(i-1)
(复数系数有前导-
)
在网上阅读了一些内容(SO,Java 教程,Java API)后,我很快得出结论,正则表达式将是最简单的解析方法,考虑到所有上述限制。 在正式方面,这个任务的正则表达式是可能的,因为我画了一个 NFA,它只接受这样的有效表达式。
我正在做这个 TDD(通过 JUnit 4),但这个测试失败了:
assertEquals("Polynomial parsed incorrectly.", poly07, PolyParser.parse(exp07));
其中 poly07
看起来像这样:(5-5i)x^2-x-1
.
这是正在引发的异常:
java.lang.NumberFormatException: For input string: "5-5"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at PolyParser.parse(PolyParser.java:55)
at PolyParserTest.testParse(PolyParserTest.java:59)
我试过调试,发现正则表达式捕获了 5-5i
(后来去掉了 i
)。然后它尝试使用参数字符串 5-5
调用 Double.parseDouble
,这会导致异常。
读完所有内容后,我不太明白需要对正则表达式进行哪些调整才能使整个节目正常运行。 此外,正则表达式的排序不像上面提到的表示约束那样,因为我想在尝试将其解析为真实系数之前查看系数是否复杂;还遇到了实数(即带小数点)被解析为整数的问题,所以正则表达式首先处理实数。
正则表达式:
public static final String POLYNOMIAL_REGEX =
"([+-])?" + // leading plus or minus
"(\()?" + // parenthesis to denote the beginning of a complex number
"([+-])?(((\d+.\d+)|\d+)i)?" + // component of coefficient, imaginary
"(((-)?\d+.\d+)|\d+)?" + // component of coefficient, real
"(\))?" + // parenthesis to denote the end of a complex number
"(x)?" + // variable
"(?:\^(\d+))?"; // power of the variable
我不会在此处 post 所有相关代码,因为它会使内容混乱。所有代码都在 GitHub 上,只需确保切换到分支 PolyParser
.
相关代码在文件中:
PolyParser.java
Polynomial.java
Complex.java
测试单元在文件PolyParserTest.java
.
正则表达式基本上无法解析表达式,因为它们无法跟踪嵌套(例如括号)。这是大多数人不知道的一课,他们是通过艰难的方式发现的。
但是,表达式很容易解析,使用自上而下的解析。请参阅我关于如何执行此操作的回答:此答案涵盖了如何进行解析,并链接到另一个讨论如何构建 AST 来表示您的表达式的答案。
第一步:编写一个语法来表示您的表达式允许的内容。您的问题中有一个特别的描述,但是语法会迫使您准确地写出合法的内容和不合法的内容。使用该语法,您可以非常轻松地编写上面建议的递归下降解析器。