한 줄의 텍스트에서 단어의 문자를 정렬할 수 있나요?

한 줄의 텍스트에서 단어의 문자를 정렬할 수 있나요?

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

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

대문자 앞에 소문자를 추가로 요구하려면 ASCII에서 'x'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하고 루프 후에 해당 변수에 대해 작업을 수행하면 중복된 옵션에 대해 여러 번 작업하는 것을 방지할 수 있습니다.

관련 정보