【问题标题】:RegEx for validating strings with multiple alphanumeric patterns用于验证具有多个字母数字模式的字符串的正则表达式
【发布时间】:2019-10-19 01:48:17
【问题描述】:

我正在制作一个机器人,我希望该机器人能够跟踪团队开支。我需要能够告诉机器人支付的金额和参与者(即输入支付的用户的列表)。参与者必须是取自大写拉丁字母的正好两个字母的序列(不允许使用数字或其他符号)。

示例:假设我和朋友 FH、GT、YU、WQ 和 CS 出去吃午饭。为了告诉机器人我们一起吃午饭,我将输入支付的总金额,然后输入“|”,然后输入除我之外参与活动的相关人员(如 FH、GT、YU、WQ、 CS)。 如果我愿意(虽然这不是必需的),我还可以在名称列表之后放置一个空格并写下事件的名称:如果存在,事件的名称必须始终用双引号 (") 括起来。

例如,这是一个有效的输入:

 65|FH,GT,YU,WQ,CS "lunch out"

所以格式是:数字、|、名称(用逗号分隔)、空格、事件名称。 (最后两个是可选的)。

数字必须始终为正数(出于显而易见的原因),它可以是整数(例如 65)或小数(例如 65.7、65.32 等)。如果数字是十进制数,则小数点后最多可有 2 位。

所有这些也是有效的输入:

65|FH,GT,YU,WQ,CS 
34.56|FH,GT "club night"
120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"

同一参与者不能被多次提及,因此以下输入无效。

65|FH,GT,YU,WQ,CS,GT

简而言之:命令应该以金额开头,后跟分隔符 |,然后是用户支付的人员列表。插入描述费用的消息是可选的。

有无数个有效的输入。它们都会有所不同,但它们都将遵循上述规则(没有提到两次参与者,每个参与者用逗号分隔,金额是整数或小数点后最多 2 位的小数等。 )。

但是,我似乎无法“捕捉”它们的共同点(它们的“格式”遵循我所说的规则),以便机器人能够区分有效输入和无效输入。我正在考虑使用正则表达式。我对正则表达式不太熟悉,但在我看来,正则表达式无法捕获输入可以具有的所有可能形式(例如,名称的数量、金额中的小数位数、可选名称事件等)

我应该如何进行?

【问题讨论】:

  • 这是我能得到的最接近的:^[\d.]+\|([A-Z]{2},)*([A-Z]{2})(?: "[\s\w]+")?$。这不会处理重复的字符组,但 RegEx 专家可能也知道如何处理这个问题。这是上述查询的demo
  • 非常感谢@SaschaM78!这很棒。我注意到它不排除小数点后超过 2 位的数字(例如 54.678),也不排除像“50”这样的数字。或“32”。 (即有小数点但没有小数点的数字)。您是否知道如何编辑您的正则表达式以排除这些实例?
  • 是的,你是对的,我错过了那部分。更新后的正则表达式为:^\d+(?:\.\d{1,2}){0,1}\|([A-Z]{2},)*([A-Z]{2})(?: "[\s\w]+")?$(也在演示中更新)。

标签: javascript regex regex-lookarounds regex-group regex-greedy


【解决方案1】:

也许可以用正则表达式处理重复,但为了更容易,我将使用split 并改为循环

var txt = `65|FH,GT,YU,WQ,CS
34.56|FH,GT "club night"
65|FH,GT,YU,WQ,CS,GT "this is not valid"
65|AH,GT,YU,AH
120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"`

var lines = {
  valid: [],
  notValid: []
};

txt.split("\n").forEach(line => {
  var isValid = true,
    persons = [],
    l = line.trim().replace(/.*\|([\w,]+)(\s".*)?/, "$1")

  l.split(/[,\s]/).forEach(p => {
    if (persons.includes(p))
      isValid = false;
    persons.push(p)
  })

  if (isValid)
    lines.valid.push(line)
  else
    lines.notValid.push(line)
})

console.log(lines)

【讨论】:

    【解决方案2】:

    这句话很有意思。我们将使用我们拥有的模式来解决这个问题,其中包括数字后跟管道:

    (\d+(\.\d+)?)\|
    

    不希望出现的重复两个字母:

    (([A-Z]{2}),?).*?(\1)
    

    所需的重复两个字母:

    (([A-Z]{2}),?)
    

    引号中的可选词:

    \s+"[\w\s]+"
    

    我们可以使用更改:

    (\d+(\.\d+)?)\||(([A-Z]{2}),?).*?(\1)|(([A-Z]{2}),?)|\s+"[\w\s]+"
    

    只要第二部分不是undefined,则该字符串无效,否则有效,我们将编写其余问题的脚本。

    Demo

    测试

    const regex = /(\d+(\.\d+)?)\||(([A-Z]{2}),?).*?(\1)|(([A-Z]{2}),?)|\s+"[\w\s]+"/gm;
    const str = `65|FH,GT,YU,WQ,CS 
    34.56|FH,GT "club night"
    120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"
    
    65|FH,GT,YU,WQ,CS,GT`;
    let m;
    
    while ((m = regex.exec(str)) !== null) {
        // This is necessary to avoid infinite loops with zero-width matches
        if (m.index === regex.lastIndex) {
            regex.lastIndex++;
        }
        
        // The result can be accessed through the `m`-variable.
        m.forEach((match, groupIndex) => {
            console.log(`Found match, group ${groupIndex}: ${match}`);
        });
    }

    正则表达式电路

    jex.im 可视化正则表达式:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多