CSV를 분할하고 싶지만 중괄호 그룹 내의 쉼표 일치를 무시하고 각 목록 구성원을 반복합니다. 아래 코드는 훌륭하게 작동하지만 중괄호 그룹 내의 쉼표를 고려하지 않습니다.
가정:
- 여기 있을 것이다언제나일치하는 버팀대 쌍입니다. 즉,
{{ {a,b,c}, x
will 과 같은 입력이아니요발생하다.
예상 출력:
Word='{0,1}'
Word='alpha'
Word='{(x,y,z)}'
Word='{{1,2,3}, {a,b,c}}'
인용하다:
- 공백 대신 쉼표로 목록을 분할하는 방법
- 혹시 모르니 Mac OS 10.9.5를 사용하고 있습니다.
암호:
#!/bin/bash
#TEST_STRING="alpha, beta, gamma" ## <--- works great for simple case
TEST_STRING="{0,1}, alpha, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
echo "${TEST_STRING}" | sed -n 1'p' | tr ',' '\n' | while read Extracted_Word; do
printf "Word='%s'\n" "${Extracted_Word}"
done
나는 123의 (현재 삭제된) 솔루션을 적용해 보았습니다.
#!/bin/bash
#TEST_STRING="alpha, beta, gamma" ## <--- works great for simple case
TEST_STRING="{0,1}, alpha, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
echo "${TEST_STRING}" \
| sed -n 1'p' \
| sed 's/\({[^}]*\({[^}]*}[^}]*\)*} *\)\(,\|$\) */\1\n/g;:1;s/\(\n[^{}]*\), */\1\n/;t1' \
| tr ',' '\n' \
| while read Extracted_Word; do
printf "Word='%s'\n" "${Extracted_Word}"
done
하지만 이로 인해 다음과 같은 오류 메시지가 생성됩니다.
./testcsv.sh
sed: 1: "s/\({[^}]*\({[^}]*}[^}] ...": bad flag in substitute command: ':'
./testcsv.sh: line 18: {{ {a,b,c}, x: command not found
답변1
순수한 시도세게 때리다
#!/bin/bash
TEST_STRING="{0,1}, alpha, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
TEST_STRING="$TEST_STRING"","
count=0
newword=''
while [ "${TEST_STRING::1}" ] ; do
l="${TEST_STRING::1}"
TEST_STRING=${TEST_STRING:1}
[ "$l" = '{' ] && ((count++))
[ "$l" = '}' ] && ((count--))
if [ "$l" = ',' ] && ! ((count)) ; then
echo "Word='$newword'"
newword=''
else
if [ "$newword" ] || [ "$l" != " " ] ; then
newword="$newword""$l"
fi
fi
done
답변2
다음은 예제를 분할할 sed 스크립트입니다.
#!/bin/sed -Ef
# replace all commas with newlines
s/,/\
/g
# Do we need to re-join any lines?
:loop
# Unmatched brace containing possibly another (matched) level of
# braces:
s/(\{([^{}]|\{[^{}]*\})*)\
/\1,/
tloop
# remove any leading space
s/\n */\
/g
# At first line, print result, then exit.
1q
경고: 질문의 설명에 따라 두 가지 수준의 중괄호만 처리합니다.
시험:
$ ./259252.sed <<<'{0,1}, alpha, {(x,y,z)}, {{1,2,3}, {a,b,c}}'
{0,1}
alpha
{(x,y,z)}
{{1,2,3}, {a,b,c}}
첫 번째 줄을 처리한 후 종료되는 것을 보여줍니다.
$ ./259252.sed <<<$'a,b,c\nd,e,f'
a
b
c
나는 이것을 Linux에서 실행하고 다음 답변을 사용하고 있습니다.Mac OSX의 sed와 다른 "표준" sed의 차이점은 무엇입니까?MacOS로 포팅하세요. 이것이 작동하지 않으면이 답변brew install gnu-sed
sed를 사용하여 GNU를 설치 한 후 호출하는 gsed
대신 사용하는 것이 좋습니다 .sed
사용 중:
#!/bin/bash
TEST_STRING="{0,1}, alpha, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
echo "${TEST_STRING}" | sed -E -f 259252.sed | while read Extracted_Word; do
printf "Word='%s'\n" "${Extracted_Word}"
done
이것은 만든다:
Word='{0,1}'
Word='alpha'
Word='{(x,y,z)}'
Word='{{1,2,3}, {a,b,c}}'
답변3
str='{0,1},alpha,{(x,y,z)},{{1,2,3},{a,b,c}}'
OPTIND=1 l=0 r=0; set ""
while getopts : na -"$str"
do [ "$l" -gt "$r" ]
case $?$OPTARG in
(1,) ! l=0 r=0 ;;
(0}) r=$((r+1)) ;;
(?{) l=$((l+1)) ;;
esac &&
set -- "$@$OPTARG" ||
set -- "$@" ""
done; printf %s\\n "$@"
dash
버그가 있으며 다음과 같은 것이 필요합니다.
set -- "$@" ""; str=${str#?}
...하지만 그 외에는 위의 작업이 매우 빠르고 기본적으로 모든 POSIX 셸에서 작동하며 매우 간단해야 합니다. 일치하지 않는 쌍도 처리해야 합니다.(꼭 그럴 필요가 없더라도)}
선행 항목 앞에 나타나는 a 를 무시하여 특별히 인식합니다 {
.
{0,1}
alpha
{(x,y,z)}
{{1,2,3},{a,b,c}}
접두사 문자열과 주변 따옴표를 얻으려면 다음을 바꿀 수 있습니다.
printf "Word='%s'\n" "$@"
... printf %s\\n "$@"
위에 사용된 것입니다. 여기에 예제 값이 주어지면 $str
다음이 인쇄됩니다.
Word='{0,1}'
Word='alpha'
Word='{(x,y,z)}'
Word='{{1,2,3},{a,b,c}}'
당신은 더 결심했을 수도 있습니다 ...
for W do alias "Word=$W" Word; done
...결과는...
Word='{0,1}'
Word=alpha
Word='{(x,y,z)}'
Word='{{1,2,3},{a,b,c}}'
...필요에 따라 인용하고 포함된 큰 따옴표도 올바르게 인용합니다.( 그러나 를 사용하는 경우 bash
먼저 이 작업을 수행해야 할 수도 있습니다 set --posix
).
그래서 시연을 하자면...
str="{0,1
}}, {,}alph}'a, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
OPTIND=1 l=0 r=0; set ""
while getopts : na -"$str"
do [ "$l" -gt "$r" ]
case $?$OPTARG in
(1,) ! l=0 r=0 ;;
(0}) r=$((r+1)) ;;
(?{) l=$((l+1)) ;;
esac &&
set -- "$@$OPTARG" ||
set -- "$@" ""
done; for W do alias "Word=${W# }" Word
done
Word='{0,1
}}'
Word='{,}alph}'\''a'
Word='{(x,y,z)}'
Word='{{1,2,3}, {a,b,c}}'
...선행 공백 처리도 매우 간단합니다...
답변4
또 다른 bash 솔루션:
- 일치하지 않는 중괄호 쌍을 처리합니다
{
. - 하나 이상의 여는 중괄호가 나타날 때까지는 닫는 중괄호가 허용되지 않습니다.
- 줄 끝에서 중괄호 개수를 0으로 재설정합니다.
- 여는 중괄호보다 닫는 중괄호가 더 많은 경우 쉼표는 유효한 쉼표로 허용됩니다.
- 솔루션 앞의 공백이 제거됩니다.
- 결과 단어가 인용됩니다.
암호:
str="}}{0,1}}, {,}alph}'a"
fin='false' d='0'
until $fin
do IFS= read -r -d '' -n 1 a || fin='true'
if [[ $a == '{' ]] ; then (( d++ )) ; fi ### count openning braces.
if [[ $a == ',' ]] && (( d<1 )) || $fin ### ',' out of braces or end.
then $fin && s="${s%$'\n'}" ### removing a last newline.
set -- "$@" "$s" ### store in an array.
unset a s d ### unset working variables.
fi
if [[ $a == '}' ]] && ((d>0)); then ((d--)); fi ### close braces.
s="$s$a"
done <<<"$str"
printf 'Word=%q\n' "${@# }" ### print a quoted value removing front space.
산출:
Word=\}\}\{0\,1\}\}
Word=\{\,\}alph\}\'a
아니면 좀 더 신비한 것:
str="{0,1
}}, {,}alph}'a, {(x,y,z)}, {{1,2,3}, {a,b,c}}"
fin='false' d='0'
until $fin
do IFS= read -r -d '' -n 1 a || fin='true'
[[ $a == '{' ]] && (( d++ )) ### count openning braces.
[[ $a == ',' ]] && (( d<1 )) || $fin && { ### ',' no braces (or end).
$fin && s="${s%$'\n'}" ### removing a last newline.
set -- "$@" "$s" ### store in an array.
unset a s d ### unset working variables.
}
[[ $a == '}' ]] && (( d>0 )) && ((d--)) ### substract closing braces.
s="$s$a"
done <<<"$str"
printf 'Word=%q\n' "${@# }" ### print a quoted value with front space removed.
결과:
Word=$'{0,1\n\n}}'
Word=\{\,\}alph\}\'a
Word=\{\(x\,y\,z\)\}
Word=\{\{1\,2\,3\}\,\ \{a\,b\,c\}\}