패턴 일치에서 중복 문자 제외

패턴 일치에서 중복 문자 제외

문자 세트의 문자를 단 한 번만 일치시킬 수 있는 정규 표현식이 있습니까? 즉, 캐릭터가 발견되면 세트에서 제거됩니다.

grep이 이 작업을 수행할 수 없는 경우 이를 수행할 수 있는 내장 유틸리티가 있습니까?

예:

Characters to match only once:   spine

입력하다:

spine
spines
spin
pine
seep 
spins

산출:

spine
spin
pine

편집하다:
이 출력을 얻는 방법은 여러 가지가 있지만(아래 예 참조) 일치시키려는 각 패턴에 대해 사용자 정의 명령을 만들지 않고도 이를 달성할 수 있는 방법을 찾고 있습니다.

grep '[spine]' input_file | grep -v 's.*s' | ... | grep -v 'e.*e'

답변1

그리고일반적인 표현수학적으로는 가능하지만 정규식의 크기는 알파벳 크기에 비해 기하급수적으로 늘어나서 실용적이지 않습니다.

부정을 사용하는 간단한 방법이 있습니다.역참조.

grep '[spine]' | grep -Ev '([spine]).*\1'

첫 번째 grep는 하나 이상의 을 포함하는 행을 선택하고 einps, 두 번째는 grep2개 이상을 포함하는 행을 거부합니다(예: and는 허용 spinal tap하지만 or spend는 허용하지 않음 ).foobarsee

답변2

귀하의 표현에 영감을 받아 egrep을 사용하여 더 짧은 표현을 생각해 낼 수 있습니다.

egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE

이는 다음과 같습니다.

sed /s.*s/d;/p.*p/d;/i.*i/d;/n.*n/d;/e.*e/d; FILE

다음은 입력에서 sed 명령을 자동으로 생성하는 방법입니다.

#!/bin/bash
word=$1
file=$2
expr=$(for c in $(echo $word | sed 's/./& /g'); do echo -n "/"$c".*"$c"/d;"; done);
sed $expr $file 

grep을 사용하여 유사한 접근 방식을 시도했지만 쉘이 변수에서 grep 패턴을 가져오도록 설득할 수 없었지만 이를 에코하고 잘라내어 붙여넣기를 통해 결과를 삽입하면 명령이 작동합니다.

expr="'("$(for c in $(echo $wort | sed 's/./& /g'); do echo -n $c".*"$c"|"; done)

egrep -v ${expr/%|/)\'} FILE
# doesn't work, filters nothing, whole file is printed
# check:    
echo egrep -v $(echo $exp) FILE 
egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE
# manually: 
egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE
spine
spin
pine

제가 실수를 했을 수도 있고, 변수 확장에 실수를 했을 수도 있습니다.

답변3

이는 문자열이 무엇인지 미리 알 필요가 없는 비정규식 접근 방식입니다. 가장 효율적이라고 말할 수는 없지만 내 요구 사항에는 충분히 빠릅니다.

$ (echo a;echo abc;echo aabc;echo def;echo two words;echo one pair) | awk '
>   {
>     split($0,a,"");
>     n=asort(a);
>     for(i=1;i<=n;i++){
>       if(a[i]==a[i+1]){
>         next
>       }
>     }
>   }
>   n'
a
abc
def
one pair

그 기능은 각 행을 $0배열로 분할한 a다음 배열을 정렬하고 n배열의 길이를 반환하는 것입니다. 그런 다음 배열을 반복하고 정렬된 배열에서 인접한 두 문자가 동일하면 다음 단어로 종료됩니다. 단어 전체를 통과하면 (전체) 입력 줄이 인쇄됩니다. 3개 이상의 단어로 구성된 줄은 반복되는 공백으로 인해 항상 인쇄되지 않습니다.

예 - 반복되는 문자가 없는 다섯 글자 단어를 모두 찾습니다.

$ grep '^.....$' /usr/share/dict/words | tr '[A-Z]' '[a-z]' | awk '{split($1,a,"");n=asort(a);for(i=1;i<=n;i++){if(a[i]==a[i+1]){next}}}n' | head -5
abhor
abide
abies
abilo
abler

관련 정보