【问题标题】:Regexp for multiple keywords matching多个关键字匹配的正则表达式
【发布时间】:2014-11-18 12:31:00
【问题描述】:

我有以下情况,我需要从以username=xxx;password=yyy; 开头的字符串中获取用户名和密码

用户名和密码没有限制,除了;应该是每个关键字的分隔符,用户名后面总是username=,密码后面总是password=

我尝试构建以下内容,但我设法只得到部分想要的结果

set value "colour=blue;
age=25;
name=anthony;
username=firstuser;
username=hisuser;
password=test123"

set value2 "colour=blue;
age=25;
name=brothersofanthony;
username=seconduser;
password=test123;"

set value3 "username=user-3"

set value4 "username=user4"


regexp -nocase -- {\y(?:username=|password=)[a-z0-9]+} $value match match2
puts "value is $match and match2 is $match2"

regexp -nocase -- {\y(?:username=|password=)[a-z0-9]+} $value2 match match2
puts "value 2 is $match and match2 is $match2"

regexp -nocase -- {\y(?:username=|password=)[a-z0-9]+} $value3 match match2
puts "value 3 is $match and match2 is $match2"

regexp -nocase -- {\y(?:username=|password=)[a-z0-9]+} $value4 match match2
puts "value 4 is $match and match2 is $match2"

我正在尝试构建一个可以返回用户名和密码的正则表达式。使用上面的正则表达式,如果用户名有[a-z0-9],我设法只得到正确结果的“用户名”,而实际上它也可以是不同的符号(除了;,因为它是分隔符)

如果在字符串中发现多次出现(例如value,有两个用户名,则应考虑第一个用户名)

上述正则表达式的第二个问题是它没有显示“密码”值,它需要与用户名具有相同的条件。

如何改进上述正则表达式?

【问题讨论】:

  • 一个value可以有2个用户名和1个密码?您到底期望输出什么?
  • @Jerry 我放这个是为了确保只检索到第一个用户名。
  • 这是一条有用的信息!好的,我会在几秒钟内写一个答案
  • 还有一个问题,对于value3value4,是否因为没有密码而需要匹配?用户名总是在密码之前吗?
  • @Jerry :如果实际上只找到用户名或密码,它应该只返回一个。如果两者都找到,它会返回两者。如果没有找到,它应该返回 None

标签: regex tcl


【解决方案1】:

在这种特殊情况下,您需要分隔匹配项,否则您将无法区分 usernamepassword。我建议使用一个正则表达式作为用户名,另一个作为密码。接下来,更改正则表达式,使字符类为[^;]+ 而不是[a-z0-9]+,以匹配除; 之外的所有字符。

set value "colour=blue;
age=25;
name=anthony;
username=firstuser;
username=hisuser;
password=test123"

regexp -nocase -- {\yusername=([^;]+)} $value - username
regexp -nocase -- {\ypassword=([^;]+)} $value - password
puts $username
puts $password
# => firstuser
# => test123

【讨论】:

  • 不知何故,单个(但更复杂的)正则表达式 regexp -- {^(?=.*?\yusername=([^;]+))(?=.*?\ypassword=([^;]+))} $value - username password 无法按预期工作。如果捕获组处于前瞻中,似乎不会保存它们。
【解决方案2】:

像往常一样,正则表达式的工作量确实比必要的要多。

proc getUsernameAndPassword record {
    set res [dict create]
    foreach {keyword value} [split [string map [list \n {}] $record] \;=] {
        if {$keyword in {username password} && $keyword ni [dict keys $res]} {
            dict set res $keyword $value
        }
    }
    if {[dict size $res]} {
        return $res
    } else {
        return None
    }
}

如果在记录中找不到用户名或密码,此命令将返回字符串None。如果在记录中找到任一值,该命令将返回一个列表,其中包含相关关键字(usernamepassword),后跟该值。如果找到两个值,列表将包含两个关键字,每个关键字后跟值。

该命令通过删除所有换行符,然后在每个分号或等号处拆分字符串,将您的记录转换为 key-val 列表。检查每个键值对以查看它们的键是username 还是password 并且 如果关键字尚未添加到res。如果两个条件都为真,则关键字和值存储在res 中。如果在命令结束时,res 中存储了任何内容,则返回字典:否则返回 None

文档:dictforeachiflistprocreturnsetsplitstring

【讨论】:

    【解决方案3】:

    我认为最简单的方法是

    set RE {^(username|password)=(.+?)(?:;|$)}
    foreach {matched field contents} [regexp -all -inline -line $RE $value] {
        puts "I found '$field' which held '$contents'"
    }
    

    在您的第一个示例中,这会产生:

    我找到了包含“firstuser”的“用户名” 我找到了包含“hisuser”的“用户名” 我找到了包含“test123”的“密码”

    我们使用-all 匹配每个可能的位置,而不仅仅是第一个,-inline 用于返回匹配项(因此我们可以foreach 对它们进行处理),-line 用于生成 RE引擎与行中的事物不匹配(影响.^$)。

    当一个字段出现两次时,您必须决定要做什么,但这不再是匹配,而是解析更高级别的概念。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-21
      • 2015-04-14
      相关资源
      最近更新 更多