【发布时间】:2011-11-25 22:56:19
【问题描述】:
我有一个很大的字符串,比如
ABCDEFGHIJKLM...
我想以这种方式将其拆分为长度为 5 的子字符串:
>1
ABCDE
>2
BCDEF
>3
CDEFG
[...]
【问题讨论】:
我有一个很大的字符串,比如
ABCDEFGHIJKLM...
我想以这种方式将其拆分为长度为 5 的子字符串:
>1
ABCDE
>2
BCDEF
>3
CDEFG
[...]
【问题讨论】:
${string:position:length}从
$string中提取$length子字符串的字符$position.stringZ=abcABC123ABCabc # 0123456789..... # 0-based indexing. echo ${stringZ:0} # abcABC123ABCabc echo ${stringZ:1} # bcABC123ABCabc echo ${stringZ:7} # 23ABCabc echo ${stringZ:7:3} # 23A # Three characters of substring.
-- 来自 Mendel Cooper 的 Advanced Bash-Scripting Guide 中的 Manipulating Strings
然后使用循环遍历,在位置上加1,提取每个长度为5的子串。
end=$(( ${#stringZ} - 5 ))
for i in $(seq 0 $end); do
echo ${stringZ:$i:5}
done
【讨论】:
fold -w5 应该可以解决问题。
$ echo "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | fold -w5
ABCDE
FGHIJ
KLMNO
PQRST
UVWXY
Z
干杯!
【讨论】:
sed 可以一键搞定:
$ echo "abcdefghijklmnopqr"|sed -r 's/(.{5})/\1 /g'
abcde fghij klmno pqr
或
取决于您的需求:
$ echo "abcdefghijklmnopqr"|sed -r 's/(.{5})/\1\n/g'
abcde
fghij
klmno
pqr
更新
我以为这只是简单的拆分字符串问题,没有仔细阅读问题。现在它应该可以满足您的需求:
还是一枪,但这次是 awk:
$ echo "abcdefghijklmnopqr"|awk '{while(length($0)>=5){print substr($0,1,5);gsub(/^./,"")}}'
abcde
bcdef
cdefg
defgh
efghi
fghij
ghijk
hijkl
ijklm
jklmn
klmno
lmnop
mnopq
nopqr
【讨论】:
...或使用split 命令:
$ ls
$ echo "abcdefghijklmnopqr" | split -b5
$ ls
xaa xab xac xad
$ cat xaa
abcde
split 也对文件进行操作...
【讨论】:
在 bash 中:
s=ABCDEFGHIJ
for (( i=0; i < ${#s}-4; i++ )); do
printf ">%d\n%s\n" $((i+1)) ${s:$i:5}
done
输出
>1
ABCDE
>2
BCDEF
>3
CDEFG
>4
DEFGH
>5
EFGHI
>6
FGHIJ
【讨论】:
sed 会这样做吗?:
$ sed 's/\(.....\)/\1\n/g' < filecontaininghugestring
【讨论】:
sed 's/...../&\n/g' filename 足够了,但不能解决问题(还需要理解\n,这不是所有sed 实现都可以做到的)。
str=ABCDEFGHIJKLM
splitfive(){ echo "${1:$2:5}" ; }
for (( i=0 ; i < ${#str} ; i++ )) ; do splitfive "$str" $i ; done
或者,也许您想对结果进行更智能的处理
#!/usr/bin/env bash
splitstr(){
printf '%s\n' "${1:$2:$3}"
}
n=$1
offset=$2
declare -a by_fives
while IFS= read -r str ; do
for (( i=0 ; i < ${#str} ; i++ )) ; do
by_fives=("${by_fives[@]}" "$(splitstr "$str" $i $n)")
done
done
echo ${by_fives[$offset]}
然后调用它
$ split-by 5 2 <<<"ABCDEFGHIJKLM"
CDEFG
你可以从那里调整它。
编辑:C 中的简单版本,用于性能比较:
#include <stdio.h>
int main(void){
FILE* f;
int n=0;
char five[6];
five[5] = '\0';
f = fopen("inputfile", "r");
if(f!=0){
fread(&five, sizeof(char), 5, f);
while(!feof(f)){
printf("%s\n", five);
fseek(f, ++n, SEEK_SET);
fread(&five, sizeof(char), 5, f);
}
}
return 0;
}
原谅我糟糕的 C,我真的不懂这门语言。
【讨论】:
sed 可以做到:
sed -nr ':a;h;s/(.{5}).*/\1/p;g;s/.//;ta;' <<<"ABCDEFGHIJKLM" | # split string
sed '=' | sed '1~2s/^/>/' # add line numbers and insert '>'
【讨论】:
您可以使用 cut 并指定 characters 而不是 fields,然后将输出分隔符更改为您需要的任何内容,例如换行:
echo "ABCDEFGHIJKLMNOP" | cut --output-delimiter=$'\n' -c1-5,6-10,11-15
输出
ABCDE
FGHIJ
KLMNO
或
echo "ABCDEFGHIJKLMNOP" | cut --output-delimiter=$':' -c1-5,6-10,11-15
输出
ABCDE:FGHIJ:KLMNO
【讨论】:
感谢你们,我能够找到一种快速完成此任务的方法!这是我结合了这里的一些想法的解决方案:
str="ABCDEFGHIJKLMNOP"
splitfive(){
echo $1 | cut -c $2- | sed -r 's/(.{5})/\1\n/g'
}
for (( i=0; i <= 5; i++ )); do
splitfive "$str" $i
done | grep -v "^$"
[上述答案最初是添加到问题本身中的。以下是相关的 cmets。]
您的
splitfive可能会更有效率。无需管道切割,在 bash 中您可以说cut -c "$2"- <<<"$1" | sed等,它会稍微好一些。 -- sorpigal 2011 年 9 月 28 日 11:48
您的 sed 表达式也可以改进为
sed 's/...../&\n/g',它的执行速度大约是原来的两倍。 -- sorpigal 2011 年 9 月 28 日 11:56
【讨论】:
ABCDE, BCDEF... 但这会产生 ABCDE, FGHIJ...