搜索
首页后端开发GolangCode n Golang 的出现:做或不做正则表达式

受到 Shradha Agarwal 在 Byte Size Go 上的帖子的启发:这里:我决定写下我的方法,它是不同的,并且想分享它。那篇文章写得很好,解决方案紧凑而简单,我建议也先阅读该文章。

这是一个 blogvent 系列,我也很想参加 blogvent,但不确定我是否会完成这个。

介绍

嗯,现在是 Code 2024 出现的第三天,我一直在直播。我落后了两天,但正在一一解决。到目前为止,我已经在 Go 中学到了很多东西。让我们开始第三天的生活吧。

第 1 部分

任何 AOC 问题的第一部分似乎都很简单,但是一旦第二部分被揭示,真正的实现就开始令人费解(如果你不乐观或不深思熟虑的话)

今天的第 1 部分是解析一个包含 mul(X,Y) 表达式的字符串,其中 X 可以是任何 3 位数字。因此,字符串中可能有多个这样的表达式,目的是将单个表达式中的 X 和 Y 相乘并将它们相加。

Advent of Code n Golang: Do or Don

xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

在上面的例子中,有 4 个这样的表达式,如果我们将它们相乘,我们得到的答案是 161。

方法

它看起来像正则表达式模式,在字符串中查找类似表达式的模式。因此,方法是使用正则表达式模式找到此类表达式,并将数字解析为整数,然后将它们相乘,简单地。

您可以继续编写解析器来迭代字符串中的每个字符并解析标记,然后评估表达式。这是一种有效的方法,但我选择这样做是因为我不知道如何诚实地编写解析器,我也想在最后尝试该解决方案。

但对于第一部分,快速正则表达式似乎是个好主意。

构建正则表达式

第一件事是编写 mul(X,Y) 部分的正则表达式,这是第一部分中唯一具有挑战性的部分。剩下的只是简单的数学。

所以,我们需要找到 mul,然后找到 a(然后找到任意 1 到 3 位数字长的数字,然后再找到 1 到 3 位数字长的数字,最后以 a 结尾)

翻译为:

mul\((\d{1,3}),(\d{1,3})\) 

让我们细分一下:

  • mul 用于捕获字面词 mul

  • (这是表达式 mul() 中的第一个括号,如果我们想匹配它,我们需要在正则表达式中转义括号,所以我们在它之前使用。

  • 然后我们有一个匹配组 (d{1,3}) ,这将是 mul(X,Y) 中的 X:

    • 匹配组就像正则表达式中的一组匹配,基本上,如果你想捕获整个匹配中的特定部分,那么我们使用 () 将它们单独分组,这不是必需的,但有助于获得正确的事情,没有开销
    • 在本例中,我们使用匹配组来捕获 1 到 3 位数字的数字。
    • 另一种写法是 ([0-9]{1,3}) ,它也会做同样的事情,(注意: [0-9] 和 d 有一些区别,但那就是非常微妙,不会影响这个谜题,如果你仍然好奇,我更喜欢阅读这个 StackOverflow 问题)
  • 然后我们使用 , 作为 mul(X,Y) 表达式中 X 和 Y 操作数的分隔符

  • 然后我们以类似的方式将 mul(X,Y) 中的 Y 与 (d{1,3}) 匹配组进行匹配

  • 最后我们用 ) 来结束正则表达式

编码它

这非常简单,我们将行作为字符串获取,并使用 regexp.MustCompile 函数,它为我们提供了一个 Regexp 对象,该对象又具有一些与之关联的方法来查找、匹配、替换和其他可以执行的操作使用字符串上的正则表达式来完成。

一旦我们有了 mulRegex ,我们就可以使用与 regexp 包中的 Regexp 结构关联的 FindAllStringSubmatch 方法。该函数接受一个字符串来执行正则表达式,以及要返回的最大匹配数。我们想要所有结果,因此我们将它们传入 -1 以获得所有匹配项。

现在,此方法返回字符串切片的切片,每个切片都是一个匹配项,每个切片内都有一个字符串切片,其中包含匹配的字符串以及字符串中的后续匹配组(如果有)。

xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

所以,上面的函数将返回类似这样的内容

mul\((\d{1,3}),(\d{1,3})\) 

这是一个字符串列表,这些看起来像数字,但它们是 Golang 中的字符串类型。

现在我们有了这个,我们可以创建获取结果的实际逻辑部分,即解析这些表达式,将 X 和 Y 相乘并将每个表达式的结果相加。

func FindMulExpression(line string) [][]string {
  mulRegex := regexp.MustCompile(`mul\((\d{1,3}),(\d{1,3})\)`)
  return mulRegex.FindAllStringSubmatch(line, len(line))
}

这非常简单,我们迭代每个匹配项,即一个 mul(X,Y) 表达式,并将 X 和 Y 分别解析为整数并相乘,然后将获得的结果添加到分数中。我们对字符串(行)中找到的每个 mul(X,Y) 表达式执行此操作并返回最终分数。

输入

现在,示例给了我们一个字符串,但我意识到输入中有六行(单独输入),因此我们需要解析每一行并将分数相加。

请记住这一点,因为它在第 2 部分中至关重要,我花了一些时间并质疑我的存在,才意识到我们需要组合所有行才能获得结果(在第 1 部分中不是必需的,但在第 2 部分中肯定是这样)。

第2部分

这通常是出问题的地方。至少对我来说是这样。

我从一个非常幼稚的方法开始,使用永远循环并找到“做”或“不做”的索引并剥离这些部分,然后循环直到我们没有剩下“做”和“不做”。这对测试用例有效,但在实际输入上失败了。

我最终想出的方法,并通过稍微调整相同的方法来发挥作用。

方法

我想到的是在整个字符串中找到 don’() 和 do() 字符串的第一个匹配位置,我们将其删除并删除 don’t() 之后或 do() 之前的部分。这样我们就可以将字符串修剪为仅有效/启用的 mul() 表达式。

Advent of Code n Golang: Do or Don

因此,更明确定义的方法将是:

  • 查找 dont() 和 do() 表达式的位置(索引)

  • 我们需要跟踪前一个字符串是启用还是禁用,因此将保留一个标志以将启用的表达式(字符串的一部分)附加到最终结果

  • 如果没有找到,则按原样返回字符串(行)

  • 如果我们找到其中任何一个:

    • 如果我们首先发现don't(dont()出现在do()之前)

      • 如果启用标志为 true → 将字符串附加到 dont() 表达式之前
      • 然后将启用切换为 false 并修剪掉 don't() 部分 (这样我们就完成了 don't 表达式之前的所有检查,因此我们从行字符串中删除该部分)
    • 如果我们发现do先出现(do()出现在dont()之前)

      • 如果启用标志为 true → 将字符串附加到 do() 表达式之前
      • 然后将启用切换为true并修剪掉do()部分 (这样我们就完成了 do 表达式之前的所有检查,因此我们从行字符串中删除了这部分)
  • 我们这样做,直到没有剩余的线串需要检查

代码

我使用简单的 Strings.Index 来获取子字符串的第一个匹配索引,在本例中,我想要 dont() 和 do() 的第一个匹配索引。一旦我们有了两个匹配项的索引,我们就可以迭代,直到字符串中不再有任何该做或不该做的事情。

如果我们有 do 或 don ,我们会在字符串中附加 do not 之前的部分(如果启用)或在 do 之前的部分(如果启用),并相应地打开和关闭启用标志。在循环结束时,结果字符串将仅包含行/字符串的启用部分。

xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

我将这个函数传递给乘法函数,在其中我获取 mul 表达式的匹配模式并进行数学计算。

strings.Index 方法接受一个字符串和一个要在该字符串中查找的子字符串,并返回该子字符串第一个出现的实例的索引。这样我们就可以识别行字符串是否包含 do() 或 dont() 表达式,如果不包含,我们只需返回该行,如果存在它们的实例,我们循环并修剪该行之前和之后的字符串。表达式取决于该标志是启用还是禁用。

让我们举个例子并演练一下逻辑:

xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

在将结果传递给 FindMulExpression 函数后,我们使用与第一部分中使用的相同的 Multiply 函数来处理结果,该函数将返回结果行字符串中的所有 mul 表达式。

注意输入

拼图的实际输入我认为是多行,所以我们需要在所有剩余的行中保留该行的状态。或者,我们可以更聪明,创建一个大字符串并处理它。两者都是有效的并且会给出相同的结果。我只是不想增加跟踪所有状态和行的开销,所以我只是连接所有行并处理该单个字符串。

结论

本质上这是一个简单的问题,但如果您不了解正则表达式,您可能会陷入编写自己的解析器或有线字符串操作的兔子洞(就像我一样)。

这就是第三天,我将在周末甚至下周进行更多的直播解决问题。在 GitHub 上查找我的 AoC 解决方案的代码。

到那时,

快乐编码:)

以上是Code n Golang 的出现:做或不做正则表达式的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
了解Goroutines:深入研究GO的并发了解Goroutines:深入研究GO的并发May 01, 2025 am 12:18 AM

goroutinesarefunctionsormethodsthatruncurranceingo,启用效率和灯威量。1)shememanagedbodo'sruntimemultimusingmultiplexing,允许千sstorunonfewerosthreads.2)goroutinessimproverentimensImproutinesImproutinesImproveranceThroutinesImproveranceThrountinesimproveranceThroundinesImproveranceThroughEasySytaskParallowalizationAndeff

了解GO中的初始功能:目的和用法了解GO中的初始功能:目的和用法May 01, 2025 am 12:16 AM

purposeoftheInitfunctionoIsistoInitializeVariables,setUpConfigurations,orperformneccesSetarySetupBeforEtheMainFunctionExeCutes.useInitby.UseInitby:1)placingitinyourcodetorunautoamenationally oneraty oneraty oneraty on inity in ofideShortAndAndAndAndForemain,2)keepitiTshortAntAndFocusedonSimImimpletasks,3)

了解GO界面:综合指南了解GO界面:综合指南May 01, 2025 am 12:13 AM

Gointerfacesaremethodsignaturesetsthattypesmustimplement,enablingpolymorphismwithoutinheritanceforcleaner,modularcode.Theyareimplicitlysatisfied,usefulforflexibleAPIsanddecoupling,butrequirecarefulusetoavoidruntimeerrorsandmaintaintypesafety.

从恐慌中恢复:何时以及如何使用recover()从恐慌中恢复:何时以及如何使用recover()May 01, 2025 am 12:04 AM

在Go中使用recover()函数可以从panic中恢复。具体方法是:1)在defer函数中使用recover()捕获panic,避免程序崩溃;2)记录详细的错误信息以便调试;3)根据具体情况决定是否恢复程序执行;4)谨慎使用,以免影响性能。

您如何使用'字符串”包装操纵串中的琴弦?您如何使用'字符串”包装操纵串中的琴弦?Apr 30, 2025 pm 02:34 PM

本文讨论了使用GO的“字符串”软件包进行字符串操作,详细介绍了共同的功能和最佳实践,以提高效率并有效地处理Unicode。

您如何使用'加密”在Go中执行加密操作的软件包?您如何使用'加密”在Go中执行加密操作的软件包?Apr 30, 2025 pm 02:33 PM

本文使用GO的“加密”软件包详细介绍了加密操作,讨论了安全实施的关键生成,管理和最佳实践。

您如何使用'时间”处理日期和时间的包装?您如何使用'时间”处理日期和时间的包装?Apr 30, 2025 pm 02:32 PM

本文详细介绍了GO的“时间”包用于处理日期,时间和时区,包括获得当前时间,创建特定时间,解析字符串以及测量经过的时间。

您如何使用'反映”包裹检查GO中变量的类型和值?您如何使用'反映”包裹检查GO中变量的类型和值?Apr 30, 2025 pm 02:29 PM

文章讨论了使用GO的“反射”软件包进行可变检查和修改,突出显示方法和性能注意事项。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。