Chinaunix

标题: 从文本中取值求助 [打印本页]

作者: bikkuri    时间: 2014-01-27 22:13
标题: 从文本中取值求助
本帖最后由 bikkuri 于 2014-01-27 15:16 编辑

有这样一组数据:
data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
希望将每一个以空格分隔的字符串按以下方式赋值给三个变量:
$obj=":前面的字符串"
$code=":后面的部分但不包含[]部分"
$field="[和]中间的数字,如果没有[]部分,则为-1"
[]部分可能有,也可能没有

我知道可以用${}来分隔字符串,比如$obj可以通过obj=${str%%:*}来得到,
但是$code和$field可能要分隔两次,这样的话应该怎么写呢?
  1. data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. for str in $data; do
  3. obj=${str%%:*}
  4. code=${str##*:}
  5. printf "Object:%-6s Code:%-15s Field:%i\n" $obj $code $field
  6. done
复制代码
  1. Object:AAAA   Code:12K3456[1]      Field:0
  2. Object:BB     Code:2455F63         Field:0
  3. Object:CCC    Code:9452T045[3]     Field:0
  4. Object:D      Code:458J83[2]       Field:0
  5. Object:FF     Code:45245K39        Field:0
复制代码

作者: yestreenstars    时间: 2014-01-27 23:39
你给的结果跟你描述的不一样?
  1. awk '{for(i=0;i++<NF;){match($i,/([^:]+):([^[]+)\[?([^]]*)/,a);if(a[3]=="")a[3]=-1;printf "Object:%s\tCode:%s\tField:%s\n",a[1],a[2],a[3]}}' i
  2. Object:AAAA     Code:12K3456    Field:1
  3. Object:BB       Code:2455F63    Field:-1
  4. Object:CCC      Code:9452T045   Field:3
  5. Object:D        Code:458J83     Field:2
  6. Object:FF       Code:45245K39   Field:-1
复制代码

作者: bikkuri    时间: 2014-01-28 03:07
谢谢您的答复。
我给出的程序和结果只是我还在修改的脚本,并没有实现我希望的输出。
您给出的输出是我希望得到的结果,但是busybox的awk好像不支持数组,所以您的程序在busybox下的输出是不正确的:
  1. root@jinx:/tmp# data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. root@jinx:/tmp# echo $data|awk '{for(i=0;i++<NF;){match($i,/([^:]+):([^[]+)\[?([^]]*)/,a);if(a[3]=="")a[3]=-1;printf "Object:%s\tCod
  3. e:%s\tField:%s\n",a[1],a[2],a[3]}}'
  4. Object: Code:   Field:-1
  5. Object: Code:   Field:-1
  6. Object: Code:   Field:-1
  7. Object: Code:   Field:-1
  8. Object: Code:   Field:-1
  9. root@jinx:/tmp#
复制代码
而且我还要在我的脚本中对$obj,$code及$field做进一步的处理,而不是直接print出来就完事,所以希望能在我的脚本上进行修改,只要让三个变量得到正确的赋值就好。谢谢!


回复 2# yestreenstars


   
作者: bikkuri    时间: 2014-01-28 03:55
本帖最后由 bikkuri 于 2014-01-27 22:07 编辑

改了一下我的脚本,现在可以取到$obj和$code了,但是$field还是不能正确取值。
  1. data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. for str in $data; do
  3. obj=${str%:*}
  4. code=$(echo ${str#*:}|sed 's/\[.*\]//')
  5. field=$(echo ${str#*:}|sed 's/^.*\[\(.\)\]/\1/')
  6. printf "Object:%-6s Code:%-15s Field:%s\n" $obj $code $field
  7. done
复制代码
  1. Object:AAAA   Code:12K3456         Field:1
  2. Object:BB     Code:2455F63         Field:2455F63
  3. Object:CCC    Code:9452T045        Field:3
  4. Object:D      Code:458J83          Field:2
  5. Object:FF     Code:45245K39        Field:45245K39
复制代码
虽然可以用加一行[ $field == $code ] && field=-1这种耍无赖的方式得到我希望得到的输出,但是我想知道有没有不这样做就可以直接给$field正确赋值的方法?
  1. data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. for str in $data; do
  3. obj=${str%:*}
  4. code=$(echo ${str#*:}|sed 's/\[.*\]//')
  5. field=$(echo ${str#*:}|sed 's/^.*\[\(.\)\]/\1/')
  6. [ $field == $code ] && field=-1
  7. printf "Object:%-6s Code:%-15s Field:%s\n" $obj $code $field
  8. done
复制代码
  1. Object:AAAA   Code:12K3456         Field:1
  2. Object:BB     Code:2455F63         Field:-1
  3. Object:CCC    Code:9452T045        Field:3
  4. Object:D      Code:458J83          Field:2
  5. Object:FF     Code:45245K39        Field:-1
复制代码

作者: yestreenstars    时间: 2014-01-28 09:36
本帖最后由 yestreenstars 于 2014-01-28 09:36 编辑

回复 4# bikkuri

这样如何?
  1.         obj=${str%:*}
  2.         code=$(grep -oP '(?<=:)[^[]*' <<< $str)
  3.         field=$(grep -oP '(?<=\[)[^]]*' <<< $str)
  4.         field=${field:--1}
复制代码

作者: jiejie455    时间: 2014-01-28 09:37
本帖最后由 jiejie455 于 2014-01-28 09:38 编辑
  1. bash-3.2$ for i in $data; do OLDIFS=$IFS; IFS="][: ";while read a b c;do if [[ -z $c ]]; then c=-1; fi;echo -e "Object:"$a"\tCode:"$b"\tField:"$c; done <<<$i;IFS=$OLDIFS; done
  2. Object:AAAA     Code:12K3456    Field:1
  3. Object:BB       Code:2455F63    Field:-1
  4. Object:CCC      Code:9452T045   Field:3
  5. Object:D        Code:458J83     Field:2
  6. Object:FF       Code:45245K39   Field:-1
复制代码

作者: jason680    时间: 2014-01-28 09:48
回复 1# bikkuri


$ data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"

$ echo $data | perl -lane '{$_.=" ";while(m/(\w+):(\w+)(?:\[(\d+)\])?\s/g){printf"Object:%-6s Code:%-15s Fileld:%s\n",$1,$2,$3?$3:"-1"}}'

------------------------------------------------------

data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
for str in $data; do
  obj=`echo $str | awk -F'[]:[]+' '{print $1}'`
  code=`echo $str | awk -F'[]:[]+' '{print $2}'`
  field=`echo $str | awk -F'[]:[]+' '{print $3}'`
  printf "Object:%-6s Code:%-15s Field:%s\n" $obj $code ${field:--1}
done
   
作者: ly5066113    时间: 2014-01-28 10:03
回复 4# bikkuri


try:
  1. data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. for str in $data
  3. do
  4.         obj=$(echo $str | awk -F '[]:[]' '{print $1}')
  5.         code=$(echo $str | awk -F '[]:[]' '{print $2}')
  6.         field=$(echo $str | awk -F '[]:[]' '{print $3?$3:-1}')
  7.         printf "Object:%-6s Code:%-15s Field:%i\n" $obj $code $field
  8. done
复制代码
btw:
如果能说原始需求的话,结果肯定会更好。
作者: bikkuri    时间: 2014-01-28 22:46
busybox也不支持<<<这种语法。。。
  1. root@unknown1:/tmp# data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. root@unknown1:/tmp# for str in $data; do
  3. >         obj=${str%:*}
  4. >         code=$(grep -oP '(?<=:)[^[]*' <<< $str)
  5. -sh: syntax error: unexpected redirection
  6. root@unknown1:/tmp#         field=$(grep -oP '(?<=\[)[^]]*' <<< $str)
  7. -sh: syntax error: unexpected redirection
  8. root@unknown1:/tmp#         field=${field:--1}
  9. root@unknown1:/tmp# printf "Object:%-6s Code:%-15s Field:%s\n" $obj $code $field
  10. Object:FF     Code:45245K39        Field:-1
  11. root@unknown1:/tmp# done
  12. -sh: syntax error: unexpected "done"
  13. root@unknown1:/tmp#
复制代码
回复 5# yestreenstars


   
作者: bikkuri    时间: 2014-01-28 23:56
谢谢7楼和8楼的回复,你们的输出都是正确的。
好像大家都更喜欢用awk,有用sed的朋友吗?

回复 8# ly5066113


   
作者: yestreenstars    时间: 2014-01-29 00:25
回复 10# bikkuri
  1.         obj=${str%:*}
  2.         code=$(sed -r 's/.*:([^[]*).*/\1/' <<< $str)
  3.         field=$(sed -r 's/[^[]*\[?([^]]*).*/\1/' <<< $str)
  4.         field=${field:--1}
复制代码

作者: bikkuri    时间: 2014-01-29 11:38
谢谢11楼的回复,由于busybox不支持<<<语法,您的代码在修改成如下后可以正确输出。
  1. data="AAAA:12K3456[1] BB:2455F63 CCC:9452T045[3] D:458J83[2] FF:45245K39"
  2. for str in $data; do
  3.         obj=${str%:*}
  4.         code=$(echo $str|sed -r 's/.*:([^[]*).*/\1/')
  5.         field=$(echo $str|sed -r 's/[^[]*\[?([^]]*).*/\1/')
  6.         field=${field:--1}
  7. printf "Object:%-6s Code:%-15s Field:%s\n" $obj $code $field
  8. done
复制代码
回复 11# yestreenstars


   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2