多个关键字匹配的正则表达式

时间:2014-11-18 12:31:01

标签: regex tcl

我有以下情况,我需要从以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,则有两个用户名,则应考虑第一个用户名)

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

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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

像往常一样,正则表达式实际上远远超过必要的工作量。

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)的列表,后跟值。如果找到这两个值,则列表将包含两个关键字,每个关键字后跟值。

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

文档:dictforeachiflistprocreturnset,{{3 },split

答案 2 :(得分:0)

我认为最简单的方法是

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

在您的第一个样本中,这会产生:

I found 'username' which held 'firstuser'
I found 'username' which held 'hisuser'
I found 'password' which held 'test123'

我们正在使用-all来匹配每个可能的位置,而不仅仅是第一个位置,-inline以获取返回的匹配项(因此我们可以foreach覆盖它们),以及{ {1}}使RE引擎与行上的内容不匹配(影响-line.^)。

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