用于搜索和替换 lua 中的模式的字符串模式或字符串操作

String pattern or String manipulation to search and replace a pattern in lua

我得到了系统上的域列表,我只需要将包含“domain\username”的模式替换为“*”。

截至目前,我可以使用 string.gsub() 用 * 屏蔽域名,但是我应该添加什么模式以确保 domain\username 的任何存在都替换为 *

示例: 如果系统上有 2 个域 test.comwork-user.com 并且用户为 admin guest 文件具有以下详细信息:

用户尝试从 TEST\admin 登录;但应该从 work-user\user1、testing\guest 帐户登录。 域 test.com 和 WORK-USER.org 处于活动状态,TESTING 域处于非活动状态。

那么输出应该是这样的:

用户尝试从 ********* 登录;但应该从 ********\user1 登录,没有用于测试的日志\*****,帐户。 域 ****.com 和 *********.org 处于活动状态,TESTING 域处于非活动状态。

由于 Testing 和 user1 不是该系统上的域和用户名,因此不应替换它们。

我有逻辑以任何给定的格式独立替换用户名和域名,但是当它是 domain\username 的格式时我无法替换它。

获取域名后,我必须添加一些logic\pattern,以便它符合上述要求。 你能告诉我如何进行吗?

我尝试了下面的代码:

test_string="User tried to login from TEST\admin; but should have logged in from work-user\user1, No logs present for testing\guest, account. The domain test.com and WORK-USER.org are active and TESTING domain in inactive" s= "test" t=( string.gsub(s.."$DNname", "%$(%w+)", {DNname="\([%w_]+)"}) ) n=( string.gsub(s.."$DNname", "%$(%w+)", {DNname="\([%a%d]+)([%;%,%.%s]?)"}) ) print (t) print(n) r=string.match(test_string,t) res=string.match(test_string,n) print(r) print(res)

正在打印 nil,无法匹配任何模式

首先让我们谈谈为什么您的代码不起作用。

一方面,你的模式中都有一个反斜杠,所以你马上就错过了没有反斜杠的任何东西:

print(t) -- test\([%w_]+)
print(n) -- test\([%a%d]+)([%;%,%.%s]?)

但是还有一个问题。在您的测试消息中唯一应该匹配的反斜杠是 TEST\admin。但是这里的TEST都是大写的,模式匹配是区分大小写的,所以你会找不到。

答案的第一部分是制作不区分大小写的模式。这可以按如下方式完成:

s= "[Tt][Ee][Ss][Tt]"

这里我用匹配大写或小写字母的字符 class 替换了每个字母。

不过,如果我们在原始邮件中寻找这种模式会怎样?我们将遇到一个不幸的问题:我们会发现测试和测试。看起来您可能已经在写“([%;%,%.%s]?)”时遇到过这个问题。

更好的方法是边界模式。 (请注意,边界模式是 Lua 5.1 中未记录的功能。我不确定它是否在 Lua 5.0 中。它已成为 Lua 5.2 中的记录功能。)

边界模式采用一个字符集,并且只会匹配前一个字符不在集合中且下一个字符在集合中的字符之间的空格。这听起来很复杂,但基本上它可以让你找到单词的开头或结尾。

要使用边界模式,我们需要弄清楚域或用户名可能是什么样子。我们可能无法完美地做到这一点,但实际上,过度贪婪应该没问题。

s = "%f[%w-][Tt][Ee][Ss][Tt]%f[^%w-]"

这个新模式将匹配 "TEST" 和 "test",但不会匹配 "TESTING" 或 "testing"。

在继续之前,让我们看看像您的 "work-user" 这样的域可能会出现的问题。字符“-”在模式中有特殊的含义,所以我们必须对它进行转义。所有特殊字符都可以通过在前面加“%”来转义。所以,我们的工作用户模式看起来像:

s = "%f[%w-][Ww][Oo][Rr][Kk]%-[Uu][Ss][Ee][Rr]%f[^%w-]"

好吧,写出这些模式有点糟糕,所以让我们尝试编写一个函数来为我们完成它:

function string_to_pattern(str, frontier_set, ci)
  -- escape magic characters
  str = str:gsub("[][^$()%%.*+-?]", "%%%0")

  if ci then
    -- make the resulting pattern case-insensitive
    str = str:gsub("%a", function(letter)
      return "["..letter:upper()..letter:lower().."]"
    end)
  end

  if frontier_set then
    str = "%f["..frontier_set.."]"..str.."%f[^"..frontier_set.."]"
  end
  return str
end

print(string_to_pattern("work-user", "%w-", true))
  -- %f[%w-][Ww][Oo][Rr][Kk]%-[Uu][Ss][Ee][Rr]%f[^%w-]

现在我将继续提及极端情况:此模式将不匹配“-work-user”或 "work-user-"。这可能是正确的,也可能是错误的,这取决于生成的消息类型。您可以将“-”从边界集中取出,但是您会匹配例如"my-work-user"。你可以决定这是否重要,但我还没有想过如何用 Lua 的模式匹配语言来解决它。

现在,我们如何用 * 替换匹配项?这部分很简单。内置的 string.gsub 函数将允许我们用其他字符串替换我们的模式的匹配项。我们只需要生成一个由与字符一样多的 * 组成的替换字符串。

function string_to_stars(str)
  return ("*"):rep(str:len())
end

local pattern = string_to_pattern("test", "%w-", true)
print( (test_string:gsub(pattern, string_to_stars)) )

现在,还有最后一个问题。我们可以在匹配域中匹配用户。例如:

-- note that different frontier_set here
-- I don't know what the parameters for your usernames are,
-- but this matches your code
local pattern = string_to_pattern("admin", "%w_", true)
print( (test_string:gsub(pattern, string_to_stars)) )

但是,即使我们分别替换所有域和用户名,"TEST\admin" 中 "TEST" 和 "admin" 之间的反斜杠也不会被替换。我们可以这样破解:

test_string:gsub("%*\%*","***")

这会将最终输出中的“**”替换为“***”。但是,这不是很可靠,因为它可以替换原始消息中的“**”,而不是我们处理的结果。为了正确地做事,我们必须遍历所有域+用户对并做这样的事情:

test_string:gsub(domain_pattern .. "\" .. user_pattern, string_to_stars)

请注意,这必须在任何其他替换之前完成,否则域和用户名将已被替换,并且无法再匹配。

现在问题已经以这种方式解决了,让我提出一种替代方法,它反映的内容更像是我从头开始编写的内容。我认为它可能更简单,更具可读性。我们不使用模式匹配来准确找到我们的域和用户名,而是只匹配可能是域或用户名的标记,然后检查它们是否完全匹配。

local message = -- broken into multiple lines only for
                -- formatting reasons
  "User tried to login from TEST\admin; but should "
  .."have logged in from work-user\user1, No logs present "
  .."for testing\guest, account. The domain test.com and "
  .."WORK-USER.org are active and TESTING domain in inactive"

-- too greedy, but may not matter in your case
local domain_pattern = "%w[%w-]*"
-- again, not sure
local user_pattern = "[%w_]+"

-- for case-insensitivity, call :lower before inserting into the set
local domains = {["test"]=true, ["work-user"]=true}
local users = {["admin"]=true, ["guest"]=true}

local pattern = "(("..domain_pattern..")\("..user_pattern.."))"
message = message:gsub(pattern, function(whole, domain, user)
  -- only call lower if case-insensitive
  if domains[domain:lower()] and users[user:lower()] then
    return string_to_stars(whole)
  else
    return whole
  end
end)

local function replace_set(message, pattern, set, ci)
  return (message:gsub(pattern, function(str)
    if ci then str = str:lower() end
    if set[str] then
      return string_to_stars(str)
    else
      return str
    end
  end))
end

message = replace_set(message, domain_pattern, domains, true)
message = replace_set(message, user_pattern, users, true)

print(message)

注意这个例子中的模式是多么简单。我们不再需要像“[Tt]”这样不区分大小写的字符 class,因为在匹配后通过强制两个字符串都为小写 string.lower 来检查不区分大小写(这可能不是最有效的,但是,嘿,这是 Lua)。我们不再需要使用边界模式,因为贪婪匹配可以保证我们得到完整的单词。反斜杠的大小写仍然很奇怪,但我已经按照我上面建议的相同 "robust" 方式处理它。

最后一点:我不知道您为什么要这样做,但我可以猜到这是为了防止有人看到域或用户名。用 * 替换它们不一定是最好的方法。首先,如果您的消息(例如)用字母分隔,则以这些方式进行匹配可能会出现问题。对于用户友好的消息来说,这似乎不太可能,但我不知道当安全受到威胁时,你是否应该依靠它。另一件事是您没有隐藏域或用户名的长度。这也可能是不安全的主要来源。例如,用户可能会合理地猜测 ***** 是 "admin".