재귀를 사용하지 않고 Bash에서 숫자 집합의 모든 비반복 순열을 생성하는 방법을 연구 중이며 이 답변이 작동한다는 것을 알았지만 그 이유를 알고 싶습니다.
1, 2, 3이라는 세 개의 숫자가 있다고 가정해 보겠습니다.
다음 명령은 가능한 모든 비반복 순열을 생성합니다.
printf "%s\n" {1,2,3}{1,2,3}{1,2,3} | sort -u | sed '/\(.\).*\1/d'
123
132
213
231
312
321
인수가 집합 {1, 2, 3} 중괄호가 세 번 확장된 경우(가능한 모든 결과가 인쇄됨) printf
with 가 수행하는 작업을 이해합니다.%s
나는 이것이 sort -u
고유한 행만 출력한다는 것을 알고 있습니다.
sed /<pattern>/d
일치하는 행을 삭제하는 데 사용된다는 것을 알고 있습니다 <pattern>
.
나는 그 안에 있는 패턴을 읽을 때 sed
약간 혼란스러웠습니다 . 나는 읽는 방법을 알고 있지만 이 패턴이 명령에서 어떻게 작동하는지 regex
모르겠습니다 .sed
\( = literal '('
. = any character, once
\) = literal ')'
.* = any character, zero or more times
\1 = reference to first captured group
그렇다면 이 명령은 sed
이 패턴에서 고유하지 않은 값을 어떻게 제거 합니까 regex
? 실제로 캡처된 그룹이 없는데 캡처된 그룹을 어떻게 참조할 수 있는지 이해가 되지 않습니다. 리터럴 일치를 위해 패턴에 괄호를 사용합니까? 이 실행에 관한 모든 것은 명령이 나올 때까지 나에게 의미가 있었습니다 sed
.
답변1
기본적으로 이는 sed의 기본 정규 표현식(BRE)이므로 \(.\)
임의의 한 문자를 포함하는 캡처 그룹입니다. 그런 다음 .*
모든 것을 건너뛰고 \1
그룹이 일치하는 항목과 일치합니다. 모든 것을 일치시킬 수 있다면 문자는 그룹에 대해 한 번, 역참조에 대해 한 번, 두 번 나타납니다.
사실, 제가 착각한 것이 아니라면 이것은 (어떤 이유로든) 역참조를 지원하지 않기 때문에 표준 확장 정규식에서도 작동하지 않습니다. 역참조는 아래에서만 언급됩니다."BRE는 여러 문자와 일치합니다.", ERE 아래가 아니라 실제로 ERE와 동일한 기능이 내 macOS에서 작동하지 않습니다( \1
리터럴 숫자의 경우와 같습니다 1
).
$ printf "%s\n" 122 321 | sed -E -e '/(.).*\1/d'
122
그러나 GNU 도구는 ERE에서 역참조를 지원합니다.
( sort -u
여기서는 꼭 필요하지 않다고 생각합니다. 중괄호 확장 조합은 중복 없이 모든 조합을 생성해야 합니다.)
답변2
첫 번째 단계는 \(.\)
그것을 올바르게 이해하는 것입니다. 기본 정규식에서는 재생산되어야 하는 모든 문자를 캡처하는 캡처 그룹입니다 \1
. 이는 문자 그대로의 대괄호가 아닙니다.
이제 멋진 부분이 나옵니다! 각 경우에 정규식의 각 요소는 무엇과 일치합니까?
Left \(.\) .* \1 Right Result
111 1 1 1 Deleted!
112 1 1 2 Deleted!
113 1 1 3 Deleted!
121 1 2 1 Deleted!
122 1 2 2 Deleted!
123 ? ? ? NoMatch
131 1 3 1 Deleted!
132 ? ? ? NoMatch
133 1 3 3 Deleted!
위 122
, 명확하지 않은 경우: 표현식이 고정되지 않았으므로 1
왼쪽으로 이동하므로 가운데는 2
캡처링 그룹과 일치 \(.\)
하고 마지막은 2
역참조와 일치합니다 \1
. .*
(정규식과 일치하는 0개 이상의 문자)는 문자열에 맞추려고 시도하므로 이 경우 빈 문자열로 축소됩니다.
의심된다면 시도해 보세요
echo 122 | grep --color=always '\(.\).*\1'
22
색깔 만 칠해진 것을 볼 수 있습니다 .
그것을 결합하다고정된정규식 버전:
$ printf "%s\n" {1,2,3}{1,2,3}{1,2,3} | sort -u | sed '/^\(.\).*\1$/d'
112
113
122
123
132
133
...
이제 "왼쪽" 및 "오른쪽" 슬롯이 없습니다.
^\(.\) .* \1$ Result
111 1 1 1 Deleted!
112 ? ? ? NoMatch
113 ? ? ? NoMatch
121 1 2 1 Deleted!
122 ? ? ? NoMatch
123 ? ? ? NoMatch
131 1 3 1 Deleted!
132 ? ? ? NoMatch
133 ? ? ? NoMatch
이 버전에서는 첫 번째 숫자가 마지막 숫자여야 하므로 일치하는 항목이 더 적습니다.