2000 文字目の前の最後のスペースで、大きなプレーンテキストファイルを小さなファイルに分割します。

2000 文字目の前の最後のスペースで、大きなプレーンテキストファイルを小さなファイルに分割します。

要件: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単語配列を作成する前に設定(内部フィールド区切り文字)で変更できます。

関連情報