string-split-lines.sh (2711B)
1 #!/usr/bin/env bash 2 3 source ../../src/benchmark.sh 4 5 6 text=' 7 echo hello 2 8 echo hello 3 9 echo hello 4 10 11 echo hello 6 12 echo hello 7 13 echo hello 8 14 15 16 echo hello 11 17 ' 18 19 function check-split-implementation { 20 local fname=$1 ret 21 "$fname" "$text" 22 if ((${#ret[@]}!=12)); then 23 echo "$fname: wrong result" 24 declare -p ret 25 fi >&2 26 } 27 28 #------------------------------------------------------------------------------ 29 # 実装1: 改行を置換 & eval arr=() 30 31 function split1 { 32 local text=$1 sep='' esc='\' 33 if [[ $text == *$sep* ]]; then 34 a=$esc b=$esc'A' text=${text//"$a"/"$b"} 35 a=$sep b=$esc'B' text=${text//"$a"/"$b"} 36 37 text=${text//$'\n'/"$sep"} 38 GLOBIGNORE=\* IFS=$sep eval 'arr=($text$sep)' 39 40 ret=() 41 local value 42 for value in "${arr[@]}"; do 43 if [[ $value == *$esc* ]]; then 44 a=$esc'B' b=$sep value=${value//"$a"/"$b"} 45 a=$esc'A' b=$esc value=${value//"$a"/"$b"} 46 fi 47 ret[${#ret[@]}]=$value 48 done 49 else 50 text=${text//$'\n'/"$sep"} 51 GLOBIGNORE=\* IFS=$sep eval 'ret=($text$sep)' 52 fi 53 } 54 55 check-split-implementation split1 56 function split1.measure { split1 "$text"; } 57 ble-measure split1.measure 58 59 #------------------------------------------------------------------------------ 60 # 実装2: 正規表現で一つずつ切り出し 61 62 function split2 { 63 local text=$1 rex=$'[^\n]*' 64 ret=() 65 while :; do 66 [[ $text =~ $rex ]] 67 ret[${#ret[@]}]=$BASH_REMATCH 68 text=${text:${#BASH_REMATCH}} 69 [[ $text ]] || break 70 text=${text:1} 71 done 72 73 # 以下のようにしてみたが微妙に遅くなった。 74 # ${#BASH_REMATCH} の計算を変数に保存しても変わらない。 75 # while :; do 76 # [[ $text =~ $rex ]] 77 # ret[${#ret[@]}]=$BASH_REMATCH 78 # ((${#BASH_REMATCH}<${#text})) || break 79 # text=${text:${#BASH_REMATCH}+1} 80 # done 81 } 82 83 check-split-implementation split2 84 function split2.measure { split2 "$text"; } 85 ble-measure split2.measure 86 87 #------------------------------------------------------------------------------ 88 # 実装3: mapfile を使う 89 90 function split3 { 91 mapfile -t ret <<< "$1" 92 } 93 check-split-implementation split3 94 function split3.measure { split3 "$text"; } 95 ble-measure split3.measure 96 97 #------------------------------------------------------------------------------ 98 # 実装4: グロブパターンで一つずつ切り出し 99 100 function split4 { 101 local text=$1 value 102 ret=() 103 while :; do 104 if [[ $text == *$'\n'* ]]; then 105 value=${text%%$'\n'*} 106 ret[${#ret[@]}]=$value 107 text=${text#*$'\n'} 108 #text=${text:${#value}+1} 109 else 110 ret[${#ret[@]}]=$text 111 break 112 fi 113 done 114 } 115 check-split-implementation split4 116 function split4.measure { split4 "$text"; } 117 ble-measure split4.measure 118