テキストファイルから文字列を分割する簡単な方法は何ですか?

テキストファイルから文字列を分割する簡単な方法は何ですか?

string.txtとlengths.txtという2つのテキストファイルがあります。

文字列.txt:

abcdefghijklmnopqrstuvwxyz

長さ.txt

5
4
10
7

ファイルを受け取りたい

>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

私は200文字から56,000文字の長さの約28,000項目を作業しています。

現在私は以下を使用しています:

start=1
end=0
i=0
while read read_l
do
    let i=i+1
    let end=end+read_l
    echo -e ">Entry_$i" >>outfile.txt
    echo "$(cut -c$start-$end String.txt)" >>outfile.txt
    let start=start+read_l
    echo $i
done <lengths.txt

しかし、これは非常に非効率的です。より良いアイデアがありますか?

答え1

一般的に言えば、テキストを処理するためにシェルループを使用したくありません。。ここでは以下を使用しますperl

$ perl -lpe 'read STDIN,$_,$_; print ">Entry_" . ++$n' lengths.txt < string.txt
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

それは一つ(バッファリングを使用してread一度に1バイト(または通常のファイルの場合は複数バイト)を読み取るシェルコマンドよりも効率的です)両方のファイルを一度だけ読み取る(メモリに完全に保存せずに)コマンドは次のとおりです。シェルループで外部コマンドを実行するソリューションよりもはるかに効率的です。

-C数値がバイトではなく現在のロケールの文字である必要がある場合は、このオプションを追加してください。例のASCII文字には違いはありません。)

答え2

あなたはできます

{
  while read l<&3; do
    {
      head -c"$l"
      echo
    } 3<&-
  done 3<lengths.txt
} <String.txt

説明が必要です。

主なアイデアは、{ head ; } <file過小評価された@mikeservから使用および派生しました。回答。ただし、この場合は多くheadを使用する必要があるため、whileループが導入され、ファイルディスクリプタがわずかに調整され、head2つのファイルへの入力が渡されます(ファイルはString.txt処理する基本ファイル、行はlength.txt引数として渡されます)。オプション-c)。アイデアは、またはString.txt同じコマンドが呼び出されるたびに検索する必要がないため、速度の利点が必要です。各繰り返し後に改行文字を印刷します。headcutecho

どれだけ速いか(もしあれば)>Entry_i練習で行の間に内容を追加することです。

答え3

バッシュ、バージョン4

mapfile -t lengths <lengths.txt
string=$(< String.txt)
i=0 
n=0
for len in "${lengths[@]}"; do
    echo ">Entry_$((++n))"
    echo "${string:i:len}"
    ((i+=len))
done

出力

>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

答え4

何についてawk

次のコードを使用してというファイルを作成しますprocess.awk

function idx(i1, v1, i2, v2)
{
     # numerical index comparison, ascending order
     return (i1 - i2)
}
FNR==NR { a[FNR]=$0; next }
{ i=1;PROCINFO["sorted_in"] = "idx";
        for (j in a) {
                print ">Entry"j;
                ms=substr($0, i,a[j])
                print ms
                i=i+length(ms)
        }
}

保存と実行awk -f process.awk lengths.txt string.txt

関連情報