受到 Shradha Agarwal 在 Byte Size Go 上的帖子的启发:这里:我决定写下我的方法,它是不同的,并且想分享它。那篇文章写得很好,解决方案紧凑而简单,我建议也先阅读该文章。
这是一个 blogvent 系列,我也很想参加 blogvent,但不确定我是否会完成这个。
介绍
嗯,现在是 Code 2024 出现的第三天,我一直在直播。我落后了两天,但正在一一解决。到目前为止,我已经在 Go 中学到了很多东西。让我们开始第三天的生活吧。
第 1 部分
任何 AOC 问题的第一部分似乎都很简单,但是一旦第二部分被揭示,真正的实现就开始令人费解(如果你不乐观或不深思熟虑的话)
今天的第 1 部分是解析一个包含 mul(X,Y) 表达式的字符串,其中 X 可以是任何 3 位数字。因此,字符串中可能有多个这样的表达式,目的是将单个表达式中的 X 和 Y 相乘并将它们相加。
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() 表达式。
因此,更明确定义的方法将是:
查找 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中文网其他相关文章!

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

OpenSSL,作为广泛应用于安全通信的开源库,提供了加密算法、密钥和证书管理等功能。然而,其历史版本中存在一些已知安全漏洞,其中一些危害极大。本文将重点介绍Debian系统中OpenSSL的常见漏洞及应对措施。DebianOpenSSL已知漏洞:OpenSSL曾出现过多个严重漏洞,例如:心脏出血漏洞(CVE-2014-0160):该漏洞影响OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻击者可利用此漏洞未经授权读取服务器上的敏感信息,包括加密密钥等。

本文讨论了GO的反思软件包,用于运行时操作代码,对序列化,通用编程等有益。它警告性能成本,例如较慢的执行和更高的内存使用,建议明智的使用和最佳

本文讨论了GO中使用表驱动的测试,该方法使用测试用例表来测试具有多个输入和结果的功能。它突出了诸如提高的可读性,降低重复,可伸缩性,一致性和A

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化


热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)