我想拆分 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。如果这不起作用,那么这个答案建议您可以使用 安装 GNU sed brew install gnu-sed
,然后使用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 shell 中工作,而且非常简单。它还应该处理不匹配的对(即使你不需要)通过忽略特别识别}
出现在前导 之前的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}}'
...根据需要引用,并且也会正确引用嵌入的硬引号(不过,如果使用 a 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\}\}