텍스트 줄의 단어 내에서 문자를 정렬하는 것이 가능합니까?

텍스트 줄의 단어 내에서 문자를 정렬하는 것이 가능합니까?

따라서 가능한 모든 상황을 올바르게 처리하는지 확인하기 위해 일부 기능에 대해 실행하고 싶은 테스트 명령으로 가득 찬 파일이 있습니다. 하지만 중복된 명령을 사용하는 것은 의미가 없습니다. 여기 몇 가지 예가 있어요.

rap ,Xflg MIT X11           
rap ,XPBfl 'MITER'
rap ,Bflg share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

...내 함수 "rap"은 대시 대신 쉼표를 사용하여 문자 옵션의 시작을 표시하고 그 뒤에 몇 가지 인수가 옵니다. 이러한 옵션의 순서는 중요하지 않습니다.

rap ,Bf X11
rap ,fB X11

...완전히 같은 명령입니다. 물론 파일에서 중복된 줄을 제거하는 것은 쉽지만 위의 문제를 피하기 위해 내가 원하는 것은 위의 결과가 되도록 옵션을 알파벳순으로 정렬하는 것입니다.

rap ,Bf X11
rap ,Bf X11

...그런 다음 중복된 항목을 삭제할 수 있습니다. 영웅주의 없이 그런 일을 성취하는 것이 가능합니까? 이는 옵션 목록을 정렬하는 것이 아니라 옵션 자체를 정렬하는 것입니다.

답변1

또 다른 perl변형:

$ perl -pe 's{^rap ,\K\S+}{join "", sort split //, $&}e' file
rap ,Xfgl MIT X11
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

'x'대문자 앞에 소문자를 추가로 요구하려면 ASCII에서 is 'X' ^ 32(및 'X'is 'x' ^ 32) 라는 사실을 활용할 수 있습니다 .

$ perl -pe 's{^rap ,\K\S+}{join "", sort {(ord($a)^32) <=> (ord($b)^32)} split //, $&}e' file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

답변2

Perl을 사용하여 쉼표 뒤의 단어 문자 시퀀스를 캡처하고 결과를 배열로 분할하고 정렬하고 결과를 바꿀 수 있습니다.

$ perl -pe 's{(?<=,)(\w+)}{join "", sort split(//, $1)}e' yourfile 
rap ,Xfgl MIT X11           
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

요청에 따라 모든 대문자 옵션보다 먼저 모든 소문자 옵션을 정렬하는 (아마도 최적이 아닐 수 있는) 방법은 다음과 같습니다.

$ perl -pe 's{(?<=,)(\w+)}{@opts = split(//,$1); join "", 
    (sort grep /[[:lower:]]/,@opts), (sort grep /[^[:lower:]]/, @opts)
  }e' yourfile 
rap ,fglX MIT X11           
rap ,flBPX 'MITER'
rap ,fglB share git-grep    
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

답변3

GNU awk 사용sorted_in그리고 어쨌든 우리는 gawk를 사용하고 있기 때문에 적용할 수 있는 몇 가지 편리하지만 불필요한 확장이 있습니다.장식-정렬-비장식 관용구1소문자를 대문자 앞과 대문자 앞에 배치하여 소문자를 대문자보다 먼저 정렬한 2다음 인쇄하기 전에 이러한 장식을 다시 제거합니다.

$ cat tst.awk
BEGIN { PROCINFO["sorted_in"] = "@val_str_asc" }
match( $0, /^(\s*\S+\s*,)(\S+)(.*)/, a ) {
    gsub( /[[:lower:]]/, "1 &,", a[2] )        # Decorate
    gsub( /[[:upper:]]/, "2 &,", a[2] )

    sorted = ""
    split(a[2],opts,",")
    for ( idx in opts ) {                      # Sort
        sorted = sorted opts[idx]
    }

    gsub( /[[:digit:] ,]/, "", sorted )        # Undecorate
    $0 = a[1] sorted a[3]
}
{ print }

$ awk -f tst.awk file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

답변4

입력 파일의 쉼표를 대시로 바꾸면 옵션을 사용하여 getopts평소와 같이 rap함수를 구문 분석 할 수 있습니다.

변경은 로 수행할 수 있습니다 . 행의 시작 부분을 으로 변경 sed하면 다음과 같이 됩니다.rap ,rap -

sed 's/^rap ,/rap -/' file.in >file

. ./file그런 다음 rap함수가 이전에 선언되었다고 가정하면 스크립트에서 생성된 파일을 간단히 가져올 수 있습니다.

구문 분석 기능 rap의 옵션 :

rap () {
        OPTIND=1

        unset -v B_flag P_flag X_flag
        unset -v b_flag f_flag g_flag l_flag

        while getopts BPXbfgl opt; do
                case $opt in
                        B) B_flag=true ;;
                        P) P_flag=true ;;
                        X) X_flag=true ;;
                        b) b_flag=true ;;
                        f) f_flag=true ;;
                        g) g_flag=true ;;
                        l) l_flag=true ;;
                        *) echo 'Error' >&2; return 1
                esac
        done
        shift "$(( OPTIND - 1 ))"

        # Act on set flags here.

        if "${f_flag-false}"; then
                echo 'The -f option was used'
        fi

        # The non-options are available in "$@".

        printf 'Other argument: %s\n' "$@"
        printf -- '---\n'
}

루프에서 플래그 변수를 설정 while하고 루프 후에 해당 변수에 대해 작업을 수행하면 중복 옵션에 대한 작업을 여러 번 방지할 수 있습니다.

관련 정보