Bash: 현악을 트리오와 4중주로 나누기

Bash: 현악을 트리오와 4중주로 나누기

LSB구분 기호 없이 연속된 문자열을 3개의 문자 그룹으로 분할 Msb하고 배열에 저장하는 방법은 무엇입니까?

예를 들어 다음 bcdefghijhk과 같아야 합니다.

bc def ghi jhk   
b cdef fghi ijhk  

순수한 bash 문자열 조작을 사용하십시오. 예를 들어 순서를 유지해야 하므로 문자열을 뒤집는 것은 옵션이 아닙니다. 삼중항 jhk는 khj가 될 수 없습니다.

답변1

다음은 귀하가 요청한 방식으로 문자열을 분할하는 방법을 찾은 것입니다. 나는 이것을 Bash 서브루틴(함수라고도 함)으로 작성했습니다. 왜냐하면 다음과 같은 방법으로 자신의 스크립트에 통합할 수 있을 것 같은 느낌이 들었기 때문입니다.

#!/usr/bin/env bash

number=bcdefghijhk
chunk=2

number_parts=()  # global variable

function slice_number {
  local num="$1"
  local chk="$2"

  local len=${#num}
  local pos=0
  local chk_first=$(( len % chk ))

  # the first chunk is smaller when the number length
  # is not an exact multiple of chunk-size
  if [[ $chk_first -gt 0 ]]; then
    number_parts[${#number_parts[@]}]="${num:$pos:$chk_first}"
    pos=$(( pos + chk_first ))
  fi

  # collect the rest of the number as full-size chunks
  while (( (pos + chk) <= len )); do
    number_parts[${#number_parts[@]}]="${num:$pos:$chk}"
    pos=$(( pos + chk ))
  done
}

# call the slicing routine
slice_number "${number}" ${chunk}

# now $number_parts[] has the sliced up number
printf '%s ' "${number_parts[@]}"
echo

MSB와 LSB가 있다고 설명했기 때문에 문자열을 "숫자"라고 부르지만 이것은 문자열로 작동합니다. 나는 귀하가 요청한 그룹(3 또는 4)의 크기를 "청크" 크기라고 부릅니다.

문자열의 가장 오른쪽 끝은 전체 크기 블록이어야 하고 가장 왼쪽 끝은 부분 블록이어야 하기 때문에 처음에는 작업이 매우 어려워 보입니다. 대부분의 문자열 구문 분석은 그 반대를 원합니다. 그런 다음 총 문자열 길이를 블록 크기로 모듈로 계산하면 첫 번째(가장 왼쪽) 블록의 길이가 줄어들고 나머지 블록은 정확히 블록 크기가 된다는 것을 깨달았습니다. 첫 번째 청크는 특별한 경우일 수 있으며 나머지는 문자열을 통해 다음 슬라이스의 시작 위치를 전진시키는 간단한 루프입니다.

이 루틴은 배열의 0(첫 번째) 요소가 문자열의 가장 왼쪽 청크를 보유하고 배열의 마지막 요소가 가장 오른쪽 청크를 보유하는 배열에 청크를 저장합니다. 내 스크립트의 마지막 줄은 사용자가 지정하는 출력 유형인 공백 구분 기호(끝 부분에 후행 공백이 있음)를 사용하여 블록을 인쇄하는 예를 보여줍니다. 배열 대신 문자열을 어셈블하도록 코드를 수정할 수 있습니다.

배열은 제가 자주 사용하지만 다른 곳에서는 흔히 볼 수 없는 기술로 채워져 있습니다. 0부터 시작하는 배열에서 배열 요소의 수는 정확히 배열 끝 뒤의 다음 요소의 인덱스입니다. 즉, 새 요소를 배열 끝에 "푸시"하면 해당 인덱스가 채워집니다. 배열 할당이 복잡해 보이지만 작동합니다.

마지막으로, 이 예제 서브루틴은 지정된 문자열이나 블록 크기 매개변수에 대해 어떠한 검사도 수행하지 않습니다. 청크 크기가 0이거나 음수이거나 숫자가 아닌 문자가 있는 경우 일부 처리가 필요합니다. 청크 크기가 문자열 길이보다 크거나 같으면 서브루틴이 특별한 조치를 취해야 합니다. 문자열이 비어 있으면 처리해야 합니다.

답변2

다음에서 전환할 수 있는 옵션이 제공되는 경우 bash:zsh

$ set -o extendedglob
$ string=bcdefghijhk
$ print -r -- ${(j[])${(Oas[])${${(j[])${(Oas[])string}}//(#m)???/$MATCH }}}
bc def ghi jhk
$ print -r -- ${(j[])${(Oas[])${${(j[])${(Oas[])string}}//(#m)????/$MATCH }}}
bcd efgh ijhk

어디:

  • s[]분할하다아무것도 없다문자열이 문자 구성 요소로 나누어져 있음을 의미합니다.
  • Oa역배열 a순서 O.
  • j[]배열 요소는 연결되지 않으므로 이 3개의 연산자를 결합하면 문자열이 반전됩니다.
  • ${var//pattern/replacement}일반적으로 사용되는 ksh93 대체 연산자
  • (#m)(필요 extendedglob) 일치 항목이 에 저장됩니다 $MATCH.

문자열 길이가 니블의 정확한 배수인 경우 선행 공백이 생깁니다( 로 잘라낼 수 있음 ${result# }).

당신은 또한 볼 수 있습니다다른 관련 Q&A의 다른 방법은 여기를 참조하세요..

답변3

이것은 (주로) 수학적 문제로 이해될 수 있습니다.

범용 구문을 사용하여 특정 길이의 문자(bash에서는 단일 바이트)를 추출할 수 있습니다 ${str:start:length}. 시작과 길이는 모두 숫자입니다. 시작 위치와 주소를 지정할 문자 수를 정의하는 숫자입니다.

문자열 strwidth숫자가 주어지면 첫 번째 문자 블록의 길이는 이어야 합니다 echo $(( ${#str} % w )). 이것은 3개의 문자로 나누어질 수 없는 문자열 부분입니다.

제공된 str과 요청된 너비(3) 중 하나에 대해 다음을 얻습니다.

$ str='bcdefghijhk'
$ w=3
$ echo "$(( ${#str}%w ))"
2

이 값을 (오프셋)이라고 부르면 o다음과 같이 할 수 있습니다.

$ str='bcdefghijhk'; w=3; o=$(( ${#str}%w ))
$ for (( i=o-w ; i<=${#str} ; i+=w )); do 
    start="$(( i>0?i:0 ))";                # if the index is negative, use 0
    part="$(( i<0 ? o : w ))";             # use offset or w
    echo "${str:start:part}";              # extract one part.
  done

bc
def
ghi
jhk

예, 첫 번째 인덱스는 음수일 수 있습니다. 이는 모듈로 연산의 오프셋 값과 동일한 것으로 이해될 수 있습니다.

물론 이렇게 하면 요청된 형식으로 문자열이 인쇄되지 않습니다. 전체 프로세스를 함수에서 정의할 수 있다면 더 좋을 것입니다. 이러한 변경과 많은 감소를 통해 다음과 같이 작성할 수 있습니다.

$ cat tst.sh
#!/bin/bash --

split()
    {      
        local str=$2 w=$1 o i arr IFS=" ";
        local o=$((${#str}%w));
        arr=();
        for (( i=(o==0?0:o-w) ; i<${#str} ; i+=w )); do
            if (( i<0 )); then
                arr+=("${str:0:o}");
                continue;
            fi
            arr+=("${str:i:w}")
        done;
        printf "%s\n" "${arr[*]}";
    }
split "${@}"

$ chmod u+x tst.sh

$ ./tst.sh 3 'bcdefghijhk'
bc def ghi jhk

$ ./tst.sh 4 'bcdefghijhk'
bcd efgh ijhk

관련 정보