Byte Size Go에 대한 Shradha Agarwal의 게시물에서 영감을 얻었습니다. 여기: 이에 대한 저의 접근 방식이 다르기 때문에 이를 공유하고 싶습니다. 그 글도 잘 썼고 해결책도 콤팩트하고 간단하니 그 글도 먼저 읽어보시길 추천드려요.
그것은 blogvent 시리즈입니다. 저도 blogvent에 참여하고 싶지만 완료할 수 있을지 확신할 수 없습니다.
글쎄요, 코드 2024 출현 3일째인데, 라이브 스트리밍으로 하고 있어요. 이틀이 지났지만 하나씩 처리해 나가고 있습니다. 지금까지 저는 Go에서 많은 것을 배웠습니다. 3일차에 대해 살펴보겠습니다.
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이 됩니다.
문자열에서 표현식과 유사한 패턴을 찾는 정규식 패턴처럼 보입니다. 따라서 정규식 패턴을 사용하여 이러한 표현식을 찾고 숫자를 정수로 구문 분석한 후 간단히 곱하는 것이 접근 방식입니다.
문자열의 각 문자를 반복하고 토큰을 구문 분석한 다음 표현식을 평가하는 파서를 작성할 수 있습니다. 유효한 접근 방식이지만 솔직하게 파서를 작성하는 방법을 모르기 때문에 이 방법을 선택했습니다. 마지막에는 그 솔루션도 시도해 보고 싶습니다.
하지만 첫 번째 부분에서는 빠른 정규식을 사용하는 것이 좋은 생각인 것 같습니다.
첫 번째로 1부에서 유일하게 어려운 부분인 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가 됩니다.
그런 다음 mul(X,Y) 표현식에서 X와 Y 피연산자의 구분 기호로 ,를 사용합니다
그런 다음 (d{1,3}) 일치 그룹을 사용하여 mul(X,Y)에서 Y에 대한 일치를 유사하게 수행합니다
마지막으로 정규식을 )로 종료하여 표현식을 종료합니다
이것은 매우 간단합니다. 행을 문자열로 잡고 Regexp 개체를 제공하는 regexp.MustCompile 함수를 사용합니다. 이 함수에는 찾기, 일치, 바꾸기 및 기타 작업을 수행할 수 있는 몇 가지 메서드가 있습니다. 문자열에 대한 정규식을 사용하면 됩니다.
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) 표현식에 대해 이 작업을 수행하고 최종 점수를 반환합니다.
이제 예제에서는 단일 문자열을 제공했지만 입력(개별 입력)에 6줄이 있다는 것을 깨달았으므로 각 줄을 구문 분석하고 점수를 합산해야 했습니다.
2부에서 매우 중요하므로 이를 기억하세요. 결과를 얻으려면 모든 선을 결합해야 한다는 사실을 깨닫는 데 시간이 좀 걸리고 내 존재에 대해 의문을 제기했습니다(1부에서는 필요하지 않지만 2부에서는 확실히 필요함).
일반적으로 문제가 발생하는 곳은 바로 여기입니다. 적어도 나에게는 그랬다.
저는 매우 순진한 접근 방식으로 시작했습니다. 영원히 루프를 사용하여 해야 할 일과 하지 말아야 할 일의 색인을 찾아 해당 섹션을 제거한 다음 해야 할 일과 하지 말아야 할 일이 더 이상 남지 않을 때까지 반복했습니다. 테스트 케이스에서는 작동했지만 실제 입력에서는 실패했습니다.
드디어 생각해낸 접근방식인데, 같은 접근방식을 살짝 비틀어서 작업하고 있었습니다.
내가 생각해낸 것은 전체 문자열에서 don'() 및 do() 문자열의 첫 번째 일치 위치를 찾은 다음 이를 가져와서 don't() 뒤 또는 do() 앞 부분을 제거하는 것입니다. 이렇게 하면 문자열을 유효한/활성화된 mul() 표현식으로만 줄일 수 있습니다.
따라서 더 명확하게 정의된 접근 방식은 다음과 같습니다.
don't() 및 do() 표현식의 위치(색인) 찾기
이전 문자열이 활성화되었는지 또는 비활성화되었는지 추적해야 하므로 활성화된 표현식(문자열의 일부)을 최종 결과에 추가하는 플래그를 유지합니다
모두 발견되지 않으면 문자열(행)을 그대로 반환
둘 중 하나를 찾았다면:
do()를 먼저 찾으면(don()이 do() 앞에 나타남)
do를 먼저 찾으면(do()가 don't() 앞에 나타남)
확인할 줄 문자열이 없을 때까지 이 작업을 수행합니다
간단한 Strings.Index를 사용하여 하위 문자열에 대한 첫 번째 일치 색인을 얻었습니다. 이 경우 don't() 및 do()에 대한 첫 번째 일치 색인을 원합니다. 두 일치 항목의 인덱스가 있으면 문자열에 해야 할 일과 하지 말아야 할 일이 남지 않을 때까지 반복할 수 있습니다.
do 또는 don't가 있는 경우 문자열에 활성화된 경우 don 앞 부분을 추가하고 활성화된 경우 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() 또는 don't() 표현식이 포함되어 있는지 식별할 수 있습니다. 그렇지 않으면 단순히 해당 행을 반환하고 해당 인스턴스가 있는 경우 문자열 앞뒤를 반복하고 자릅니다. 플래그의 활성화 또는 비활성화 여부에 따른 표현식입니다.
예를 들어 논리를 살펴보겠습니다.
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
결과 행 문자열의 모든 mul 표현식을 반환하는 FindMulExpression 함수를 통해 결과를 전달한 후 첫 번째 부분에서 사용한 것과 동일한 Multiply 함수로 결과를 처리합니다.
퍼즐의 실제 입력은 여러 줄인 것으로 생각되므로 나머지 모든 줄에서 이 줄 상태를 유지해야 합니다. 또는 더 똑똑하게 하나의 큰 문자열을 만들어 처리할 수도 있습니다. 둘 다 유효하며 동일한 결과를 제공합니다. 모든 상태와 줄을 추적하는 오버헤드를 추가하고 싶지 않아서 모든 줄을 연결하고 해당 단일 문자열을 처리했습니다.
본질적으로는 간단한 문제였지만 정규 표현식을 모른다면 제가 그랬던 것처럼 직접 파서를 작성하거나 연결된 문자열 조작을 해야 하는 토끼굴에 빠질 수 있습니다.
이제 3일차입니다. 주말 동안 실시간 스트리밍 문제 해결을 더 많이 할 예정이며 다음 주에도 그럴 수도 있습니다. GitHub에서 내 AoC 솔루션에 대한 코드를 찾아보세요.
그때까지
행복한 코딩하세요 :)
위 내용은 Code n Golang의 출현: Regex를 수행하거나 수행하지 않음의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!