要件:GNUの代わりにBSDバージョンのツール。
ウェブサイトから週刊ニュースレターをスクラップし、メインセクションをインポートしてプレーンテキストに変換し、ファイルに保存するZSHスクリプトがあります。次に、ニュースレターのさまざまな部分を別々のファイル(file1.txt...)に分割し、各ファイルを適切なダッシュボードにアップロードします。これにより、特定のセクションの情報を歴史的に(手動/視覚的に)ソートできます。これらのセクションには、情報ソースへのハイパーリンクも含まれることがよくあります。ダッシュボード投稿の長さは2000文字(バイト)に制限されています。もともとはsplit -b 2000 file1.txt a
(file2.txtはb、file3.txtはc)を使用していました。
それでは、各2000文字目の最後のスペースでこのファイルを分割するにはどうすればよいですか?
これは次のように不完全かもしれません。
count 2000 characters
backup to last withespace
put everything that came before into a file
count from that whitespace 2000 more characters
backup to previous whitespace
put everything that came between last split point and this whitespace into next file
loop.
ファイルの終わりに達するまで繰り返します。
答え1
次のように見えます。
process() {
do-what-you-have-to-do-with-the-chunk $1
}
chunk_size=2000
file=file1.txt
set -o extendedglob # needed for (#cmin,max), ## and (#b)
# contents of the file trimmed of leading and trailing whitespace
text=${${$(<$file)%%[[:space:]]##}##[[:space:]]##}
while (( $#text > chunk_size )); do
if [[ $text = (#b)(?(#c0,$((chunk_size - 1)))[^[:space:]])[[:space:]]##(*) ]]; then
process $match[1]
text=$match[2]
else
print -ru2 Text cannot be split
exit 1
fi
done
if [[ -n $text ]]; then
# last chunk
process $text
done
長さは数量に基づいて計算されます。特徴、いいえバイト。バイト単位で計算できますが、set +o multibyte
これはマルチバイトの空白文字が無視されることを意味します。私の英国のロケールでは、ほとんどの空白文字は複数バイトでエンコードされていますが、最も一般的には使用されません。彼らは:
09 U+0009 CHARACTER TABULATION
0A U+000A LINE FEED
0B U+000B LINE TABULATION
0C U+000C FORM FEED
0D U+000D CARRIAGE RETURN
20 U+0020 SPACE
E1 9A 80 U+1680 OGHAM SPACE MARK
E2 80 80 U+2000 EN QUAD
E2 80 81 U+2001 EM QUAD
E2 80 82 U+2002 EN SPACE
E2 80 83 U+2003 EM SPACE
E2 80 84 U+2004 THREE-PER-EM SPACE
E2 80 85 U+2005 FOUR-PER-EM SPACE
E2 80 86 U+2006 SIX-PER-EM SPACE
E2 80 88 U+2008 PUNCTUATION SPACE
E2 80 89 U+2009 THIN SPACE
E2 80 8A U+200A HAIR SPACE
E2 80 A8 U+2028 LINE SEPARATOR
E2 80 A9 U+2029 PARAGRAPH SEPARATOR
E2 81 9F U+205F MEDIUM MATHEMATICAL SPACE
E3 80 80 U+3000 IDEOGRAPHIC SPACE
答え2
シェル言語は、入力で正確なスペースを維持する必要がない限り、アイテムを単語に分割するのに非常に熟練しています(たとえば、連続したスペースを単一のスペースにマージできます)。
前を見れば、処理が少し簡単になります。単語ごとにファイルに合ったら追加してください。それ以外の場合は、次のファイル処理を続行します。改行は次のようになります。
#!/usr/bin/env zsh
inFile=$1
fileAsWords=($(<$inFile))
outfileNum=0
outputText=
sep=
lineLen=0
eol=$'\n'
for word in $fileAsWords; do
if (( ${#outputText} + ${#sep} + ${#word} + ${#eol} > 2000 )); then
printf -v outfileName out-%04d.txt outfileNum++
print -r -- $outputText > $outfileName
outputText=
sep=
lineLen=0
fi
if (( lineLen > 0 && lineLen + ${#sep} + ${#word} > 80 )); then
sep=${eol}
lineLen=0
fi
outputText+=${sep}${word}
(( lineLen += ${#sep} + ${#word} ))
sep=' '
done
if (( ${#outputText} > 0 )); then
printf -v outfileName out-%04d.txt outfileNum
print -r -- $outputText > $outfileName
fi
URLなどの一部のアイテムにスペースを含めることができる場合は、ファイル間で分割することができます。分割に使用される文字セットは、IFS
単語配列を作成する前に設定(内部フィールド区切り文字)で変更できます。