【问题标题】:Java regular expression matches too muchJava 正则表达式匹配太多
【发布时间】:2014-10-06 05:47:21
【问题描述】:

所以我正在编写一个国际象棋PGN 解析器,但我在分解文件时遇到了麻烦。以下是一些注意事项:

我将整个文件转换成一个字符串,所以我的样子如下:

[Event "Rising Stars vs Experience"]
[Site "Amsterdam NED"]
[Date "2010.08.22"]
[Round "10"]
[White "Peter Heine Nielsen"]
[Black "Anish Giri"]
[Result "1-0"]
[ECO "E05"]
[WhiteElo "2700"]
[BlackElo "2672"]
[Annotator "Soltis, Andy"]
[PlyCount "113"]
[EventDate "2010.08.12"]

1. d4 Nf6 2. c4 e6 3. Nf3 d5 4. g3 Be7 5. Bg2 O-O 6. O-O dxc4 7. Qc2 a6 8. a4
Bd7 9. Qxc4 Bc6 10. Bg5 h6 11. Bxf6 Bxf6 12. Nc3 Bxf3 13. Bxf3 c6 14. Qb3 Ra7
15. Ne4 Bxd4 16. Rfd1 Qb6 17. Qd3 c5 18. e3 Be5 19. Rac1 Nc6 20. Nxc5 Rd8 21.
Nd7 Qxb2 22. Qc4 b5 23. axb5 axb5 24. Qxc6 Raxd7 {Diagram [#]} 25. Qxd7 (25.
Rxd7 Rxd7 26. Qxd7 Qxc1+) 25... Rxd7 26. Rc8+ (26. Rxd7 Qxc1+) 26... Kh7 27.
Rxd7 Kg6 28. h4 Qa3 29. Kg2 Kf6 30. Rb7 Qd6 31. Ra8 b4 32. Raa7 Qf8 33. h5 Bd6
34. Rd7 Be5 35. Rab7 Qe8 36. Bd1 Bc3 37. Bb3 Bd2 38. Kf1 Bc3 39. Ke2 Qg8 40.
Bc2 Qe8 41. f4 g5 42. hxg6 fxg6 43. e4 g5 44. e5+ Bxe5 45. Rf7+ Qxf7 46. fxe5+
Kg7 47. Rxf7+ Kxf7 48. g4 Kg7 49. Kf3 Kf7 50. Bb3 Ke7 51. Ke4 Kf7 52. Bd1 Kg7
53. Kd4 Kg6 54. Kc4 h5 55. gxh5+ Kf5 56. h6 Kg6 57. Bg4 1-0
.
.

一遍又一遍。我正在尝试创建一个模式,该模式将在开始时解析出标签,然后再解析移动文本。因此,在我上面列出的示例中,应该有 13 个标签,后跟 1 个匹配第一个游戏的游戏文本。随后的每场比赛都以类似的方式匹配。

我使用的正则表达式是:

private static final String PGN_PATTERN = "(^\\[\\w+\\s+\".*\"\\])+(.*(1-0|0-1))";

我认为让我感到困惑的是'.*' 表达式,我正在使用捕获游戏动作。我还没有为这部分想出一个像样的模式,所以我只想在一个字符串中捕捉游戏动作并继续下一个模式。

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 那为什么要用正则表达式呢?
  • 我走这条路是因为我认为代码会更容易 - 请随时纠正我
  • 你指定上面的逻辑。 there should be 13 tags followed by 1 game text - 我个人会遵循这个逻辑
  • 13 个标签不是必需的。这个特定的游戏中有 13 个标签。同一文件中的其他游戏可能或多或少。也许你可以回答一个答案,以及一个我可以尝试的正则表达式。
  • 实际匹配的是什么?所有游戏都在一个文件中吗?如果是这样,您可能只需将您的.*s 更改为.*?s。默认情况下,* 是贪婪的,并且会尽可能匹配。您也可以使用(?:1-0|0-1) 将其设为非捕获组。

标签: java regex parsing


【解决方案1】:

您需要启用与Pattern.compile(PGN_PATTERN, Pattern.DOTALL) 的点匹配的换行符。

无论如何,正则表达式并不是解析这个的最佳方式。

所以在我上面列出的示例中,应该有 13 个标签,后跟 1 个匹配第一个游戏的游戏文本。

但是您的正则表达式将只返回 3 个组:#1 将包含一个标签(一个组只能包含一个值),#3 将包含分数,#2 将包含很多不同的东西。

如果你只想跳过标签,你需要修复你的正则表达式:

PGN_PATTERN = "(?:^\\[\\w+\\s+\"[^\"]*\"\\]\n+)+\n*(.*?(1-0|0-1))"; 
                ^                 ^         ^    |         ^
                |                 |         |    |         |
                |                 |         |    |         -- how do you match draws?
                |                 |         |    ---- blank lines between headers and body
                |                 |         --- you need to match the lines too
                |                 ---- so it won't match all the tags at once and will be faster
                ------- we're skipping them, so (?:…)

现在group(1) 包含带有分数的移动,group(2) 包含分数本身,并且标题被忽略。

要解析标头,您需要更复杂的东西,而不是正则表达式。

【讨论】:

  • 我现在正在忽略抽奖 - 我确实启用了 DOTALL。 +1
猜你喜欢
  • 2010-11-25
  • 2013-11-25
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 2016-09-08
  • 2013-08-25
  • 2011-03-30
  • 2011-05-26
相关资源
最近更新 更多