【问题标题】:Regex with any term optional and in any order (javascript or java)任何术语可选且以任何顺序(javascript 或 java)的正则表达式
【发布时间】:2013-10-07 16:56:44
【问题描述】:

我有一个像这样的字符串 "%d-%m-%Y" ,这些术语中的任何一个都可以是任何顺序,破折号可以是另一个字符串 (%x)。 我想得到结果: "%d %m %Y" 。 我烘焙了一个简单的正则表达式,如果我将条款设为可选,它就无法正常工作: (在 chrome 控制台中执行此操作:)

"%d-%m-%Y HH:%i".replace(/.*?((%Y|%m|%d)?.*?(%Y|%m|%d)?.*?(%Y|%m|%d)?).*/, "$1    $2   $3    $4")

我有这个(%Y|%m|%d)?作为可选的 3 次 .*? (非贪婪的东西)他们之间。

如果我运行上面的代码行,输出是:

"%d    %d       "

如果我从 (%Y|%m|%d) 中删除可选标记?然后表达式按预期工作。 我需要这些条款是可选的。 有人可以向我解释一下可选标记是怎么回事,这种类型的正则表达式可以完成吗?

【问题讨论】:

  • 如果是可选的,您的意思是"%d-%m" 也合法吗?我假设"%d-%d" 是不合法的,因此我会说正则表达式在这里不是正确的工具——我不确定你是否可以使用 Java 的正则表达式引擎(或任何其他引擎)来做到这一点,即使它可能很难。
  • 是的,“%d-%m”是合法的,“%d-%d”不可能发生..
  • 那么,您需要全部 3 个,但只需要一次,以任意顺序以及介于两者之间的任何内容?
  • 是的,所有 3 2 或 1 以任何顺序排列,并且介于两者之间。 (我现在正在分析您的答案,它不会在 javascript 中替换为“”)

标签: java javascript regex


【解决方案1】:

我不确定您的要求,但也许两步法可行:

  1. 提取%d.*%m.*%Y 的排列,例如使用temp = input.replaceAll(".*(%(?:d|m|Y).*%(?:d|m|Y).*%(?:d|m|Y)).*", "$1")

  2. 替换%d%m%Y之间的内容,例如使用temp.replaceAll("(?<=%(?:d|m|Y))(.*?)(?=%(?:d|m|Y))", " ");

Java 示例:

String input ="xx %Y-%m-%d xx";    
String temp = input.replaceAll( ".*(%(?:d|m|Y).*%(?:d|m|Y).*%(?:d|m|Y)).*", "$1" );
String output = temp.replaceAll( "(?<=%(?:d|m|Y))(.*?)(?=%(?:d|m|Y))", " " );

System.out.println(output);   //results in "%Y %m %d"

注意事项: - 这需要 3 个组件,即 %d-%m 不匹配。 - "%d-%d" 仍然被允许,用正则表达式检查会很困难。

更新:以下表达式应允许 1-3 个组件:第一步中的.*?(%(?:d|m|Y)(?:.*%(?:d|m|Y)){0,2}).*

【讨论】:

  • 我的正则表达式也适用于非可选条款,但是一旦我将条款设为可选(对于 ex 只有 %Y-%d),它就会神秘地中断
  • 我认为我最好的解决方案是创建 3 个正则表达式:一个有 1 个术语,一个有 2 个术语,一个有 3 个术语。在我应用正确的正则表达式之前,我可以做 indexOf %Y,%m 和 %d 并计算它们的数量,如果有 2 个,则应用带有 2 个参数的正则表达式..
  • @OvidiuBuligan 请查看我的更新。不过,您仍然需要计算单个术语是否多次出现。
  • 出于维护目的,我认为最好使用 3 种情况(1,2,3 术语),因为它更易于理解并且也适用于 javascript 。(您的正则表达式不适用于 javascript )
猜你喜欢
  • 1970-01-01
  • 2013-09-27
  • 2013-04-13
  • 1970-01-01
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-02
相关资源
最近更新 更多