게임에 필요한 재료 목록을 가장 상위부터 가장 원시적인 재료까지 정리했습니다. 그러나 이제는 숫자를 집계하는 빠른 방법을 찾고 있습니다.
21 reinforced alloy
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 hardened metal
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 duralmin
21 aluminum dust
21 copper dust
21 aluminum
21 aluminum dust
21 compressed carbon
84 carbon
21 aluminum bronze
21 aluminum dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 aluminum
21 aluminum dust
21 corinthian bronze
21 silver dust
21 gold dust
21 copper dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 solder
21 lead dust
21 tin dust
21 lead
21 lead dust
21 billon
21 silver dust
21 copper dust
21 silver
21 silver dust
21 gold 24 carat
수집해야 할 원자재를 찾는 것이기 때문에 최상위 레벨은 중요하지 않습니다. 예를 들어, 21 hardened metal
및 는 21 damascus steel
합계를 찾고 있기 때문에 중요하지 않으며 , , 및 (이 예에서는 목록의 나머지 부분을 계산하지 않음) 원시 합계를 42 damascus steel
찾고 있기 때문에 중요하지 않습니다 .42 iron dust
42 carbon
42 iron
지금까지 나는정규식 테스트 웹사이트grep
, 하지만 결국에는 계산을 위해 웹사이트를 열 필요가 없도록 사용할 수 있게 되기를 바랍니다 . 나는 "탄소가 5번 나타나고 이것이 일치하는 선입니다"와 같은 것을 얻고 싶습니다. 탄소가 5번 나타나고 그 중 4번이 나타나고 21 carbon
1번이 이라는 것을 알면 84 carbon
이제 총 필요량을 쉽게 계산할 수 있기 때문에 더 쉽게 계산할 수 있습니다 21*4 + 84 = 168 carbon
.
나는 다른 행이 없고 그 뒤에 많은 수의 탭이 있는 행의 수를 세려고 합니다. 만약 있다면 그것은 원시가 아닐 것이기 때문입니다.
/(\t+)\d+ aluminum\n(?!\1)/g
("알루미늄"을 내가 찾으려는 원자재로 대체)
그러나 이것은 아무것도 밝혀지지 않았습니다. 정규식을 사용하여 달성하려는 목표를 달성할 수 있는 방법이 있습니까? 그렇다면 어떻게 해야 할까요?
시간 내 주셔서 감사합니다.
이것을 SO에 둘지 SE에 둘지는 잘 모르겠지만, 결국에는 사용할 수 있게 되기를 바란다는 점을 고려하면 grep
그곳이 더 적절한 곳이 아닐까 싶습니다.
답변1
Perl과 유사한 정규식을 사용하려면 실제 정규식을 사용하는 것이 좋습니다.
<your-file perl -l -0777 -ne '
while (m{^(\s*+)(\d+) (.*)$(?!\n\1\s)}mg) {
$count{$3} += $2
}
END {
printf "%4d %s\n", $count{$_}, $_ for sort keys %count
}'
이것은 만든다:
84 aluminum dust
168 carbon
42 copper
105 copper dust
21 gold 24 carat
21 gold dust
84 iron
84 iron dust
42 lead dust
63 silver dust
63 tin dust
-0777 -n
전체 입력이 흡수된다는 의미입니다 $_
. 연산자 m
의 최종 플래그는 의 시작과 끝 뿐만 아니라 각 줄의 시작과 끝에서도 m{...}
및 ^
일치를 발생시킵니다 . 플래그가 없으면 개행과 일치하는 항목이 없지만 입력에 빈 줄이 있으면 여기서 문제가 발생할 수 있다는 점에 유의하세요.$
$_
$_
s
.
\s
\s*+
예, 소급 적용되지 않은 버전입니다 \s*
. \d+
( ) 뒤의 내용은 공백과 일치할 수 없기 때문에 반드시 필요한 것은 아닙니다 .
Standard는 grep
사용 중인 것과 같은 perl과 유사한 정규식과 \d
perl RE 연산자를 지원하지 않지만 여러 줄 모드도 지원하는 이를 사용할 수 있습니다.(?!\1)
pcregrep
-o
-M
<your-file pcregrep -Mo '^(\s*+)\K.*$(?!\n\1\s)'
perl
합계 계산 과 같은 다른 작업을 위해서는 여전히 파이프가 필요하므로 모든 작업에 파이프를 사용하는 것보다 이점 awk
이 perl
거의 없습니다.
들여쓰기가 탭 및 공백과 혼합될 수 있는 경우, 입력을 이들 중 하나를 통해 전달하거나 expand
먼저 unexpand
공백 또는 탭으로 병합할 수 있습니다. 기본적으로 그들은 탭 정지를 대부분의 터미널이나 브라우저처럼 8열로 간주하지만(Stackexchange를 제외하면 귀찮게도 4열로 떨어져 있음) -t
이를 변경하는 옵션을 참조하세요.
답변2
라인의 레벨 <= 다음 요소의 레벨인 경우 라인은 "프리미"입니다. 이는 다음과 같습니다.
이전 행은 해당 레벨 <= 현재 레벨인 경우(또는 마지막 행인 경우) 초기 행입니다.
NF
마지막 필드로 필드 구분 기호 "\t", level 및 구성 요소와 함께 awk를 사용하십시오 $NF
.
awk -F '\t' 'prevlev>=NF {print primi};
{prevlev = NF; primi=$NF }
END {print $NF}'
요약하자면 다음과 같은 내용을 실행할 수 있습니다.
... | sed 's/ /\t/' | datamash -g 2 -s sum 1
답변3
Lookbehind와 Lookahead를 사용해야 합니다. 또한 한 줄씩 처리하는 대신 전체 입력을 함께 처리해야 합니다. 다음 명령은 원하는 작업을 수행해야 합니다.
grep -Pzo '(?<=\n)(\s+)(\S[^\n]*)(?!\n\1\s)' input_file
-P
Perl 구문을 활성화합니다.-z
개행 문자 대신 널 종결자를 사용하십시오.-o
일치하는 항목만 출력됩니다.(?<=\n)
줄바꿈을 찾아보세요. 대신^
일반적으로 각 줄의 시작 부분과 일치합니다. 후속 부정적인 견해의 경우 를 사용하십시오(?<!...)
. 아마도 항상 더 깊은 수준이 있기 때문에 첫 번째 줄을 무시합니다. 그렇지 않은 경우 로 보내기 전에 입력 시작 부분에 새 줄을 추가할 수 있습니다grep
. 이 작업을 수행하는 더 좋은 방법이 있을 수 있지만 다음은 하나입니다.( echo ; cat input_file ) | grep ...
(\s+)
들여쓰기 수준을 캡처합니다. 이것은 나중에 호출됩니다\1
.\s
공백과 일치합니다. 이에 대한 한 가지 잠재적인 문제는 개행 문자가 들여쓰기의 일부로 간주될 수 있다는 것입니다. 예를 들어, 이중 줄 바꿈은 단락 구분 기호로 자주 사용됩니다.\s
들여쓰기에 사용하려는 특정 공백( )으로 바꿀 수 있습니다[\ \t]
.(\S[^\n]*)
관심 있는 텍스트를 캡처하세요.\S
공백이 아닌 것과 일치합니다.[^\n]
개행 문자가 아닌 모든 문자와 일치합니다.(?!\n\1\s)
부정적인 미리보기는 다음 줄이 현재 줄보다 깊게 들여쓰기되지 않도록 보장합니다. 긍정적인 전망을 원하시면 를 사용하세요(?=...)
.