(UTF-8でエンコードされた)テキストファイルを特定の文字数に切り捨てるにはどうすればよいですか?行の長さは気にせず、単語の途中でカットすることもできます。
cut行で動作するようですが、ファイル全体が必要です。head -c文字ではなくバイトを使用します。
(UTF-8でエンコードされた)テキストファイルを特定の文字数に切り捨てるにはどうすればよいですか?行の長さは気にせず、単語の途中でカットすることもできます。
cut 行で動作するようですが、ファイル全体が必要です。head -c 文字ではなくバイトを使用します。回答:
一部のシステムには、truncateファイルを文字数ではなくバイト数に切り捨てるコマンドがあります。
perlほとんどのシステムにデフォルトでインストールされているものに頼ることができますが、私はいくつかの文字に切り捨てられるものを知りません:
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
では-Mopen=locale、ロケールの文字の概念を使用します(したがって、UTF-8文字セットを使用するロケールでは、UTF-8でエンコードされた文字です)。-CSロケールの文字セットに関係なく、I / OをUTF-8でデコード/エンコードする場合は、と置き換えます。
$/ = \1234:固定長のレコード(文字数)を指定する方法である整数への参照にレコードセパレーターを設定します。
その後、最初のレコードを読み取った後、stdinを所定の位置に切り捨て(最初のレコードの最後に)、終了します。
GNUを使用するとsed、次のことができます(ファイルにNUL文字または有効な文字を形成しないバイトシーケンスが含まれていないと仮定します。どちらもテキストファイルに当てはまります)。
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
しかし、ファイルを完全に読み取り、メモリ全体に保存し、新しいコピーを書き込むため、それははるかに効率的ではありません。
GNUと同じawk:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-e code -E /dev/null "$file" 任意のファイル名を渡す1つの方法 gawkRS='^$':丸lurみモード。有するksh93、bash又はzsh(以外のシェルを有するzshコンテンツがNULバイトを含まないと仮定すると、):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
でzsh:
read -k1234 -u0 s < $file &&
printf %s $s > $file
または:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
とksh93やbash(用心のいくつかのバージョンでは、マルチバイト文字のそれの偽のbash):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93また、<>;リダイレクト演算子を使用してファイルを書き換える代わりに、ファイルを切り捨てることができます。
IFS= read -rN1234 0<>; "$file"
最初の1234文字を印刷するための別のオプションは、UTF32BE/のような文字ごとの固定バイト数のエンコードに変換することUCS-4です。
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c標準ではありませんが、かなり一般的です。標準的な同等品はdd bs=1 count="$((1234 * 4))"、一度に1バイトずつ入力を読み取り、出力を書き込むので、効率は低下します¹。iconvは標準コマンドですが、エンコーディング名は標準化されていないため、UCS-4
いずれにせよ、出力は最大で1234文字ですが、区切りのない行で終わる可能性があるため、有効なテキストではない可能性があります。
また、これらのソリューションは文字の途中でテキストをカットしませんが、U + 0065 U + 0301(aの後に続く鋭いアクセント)で表されるように、書記素の途中でテキストを分割できます。または、分解された形式のハングル音節のグラフェン。ée
¹とパイプに使用することはできません入力bsは、使用しない限り、確実に1以外の値をiflag=fullblockGNU拡張をとして、ddそれはより速くパイプを読み取ると、短い行うことができます読み取りiconv塗りつぶし、それを
dd bs=1234 count=4
テキストファイルにUTF-8としてエンコードされたUnicodeが含まれていることがわかっている場合、最初にUTF-8をデコードしてUnicode文字エンティティのシーケンスを取得し、それらを分割する必要があります。
仕事にはPython 3.xを選択します。
Python 3.xでは、関数open()にはtext-filesencoding=を読み込むための追加のキーワード引数があります。メソッドio.TextIOBase.read()の説明は有望に見えます。
したがって、Python 3を使用すると、次のようになります。
truncated = open('/path/to/file.txt', 'rt', encoding='utf-8').read(1000)
明らかに、実際のツールはコマンドライン引数、エラー処理などを追加します。
Python 2.xを使用すると、独自のファイルのようなオブジェクトを実装し、入力ファイルを行ごとにデコードできます。
別のアプローチを追加したいと思います。おそらく最高のパフォーマンスではなく、はるかに長いが、理解しやすい:
#!/bin/bash
chars="$1"
ifile="$2"
result=$(cat "$ifile")
rcount=$(echo -n "$result" | wc -m)
while [ $rcount -ne $chars ]; do
result=${result::-1}
rcount=$(echo -n "$result" | wc -m)
done
echo "$result"
で呼び出し$ ./scriptname <desired chars> <input file>ます。
これにより、目標が達成されるまで最後の文字が1つずつ削除されます。これは、特に大きなファイルの場合、実際にはパフォーマンスが悪いようです。これを、より多くの可能性を示すアイデアとして提示したかっただけです。
wcへの途中のターゲットポイントの合計バイト数O(n ^ 2)のオーダーでカウントします。増加または減少する変数などを使用して、線形検索の代わりにバイナリ検索を行うことができるはず echo -n "${result::-$chop}" | wc -mです。(そして、ファイルの内容がで始まっていて-eも、おそらくを使用している場合でも、安全を確保してくださいprintf)。ただし、各入力文字を一度だけ見るメソッドに勝るものはないので、おそらくそれだけの価値はありません。
$result、目的の長さに一致するまでcharごとにcharを追加することもできますが、必要な長さが大きい数値の場合は、同様に非効率的です。
$desired_charsローエンドまたはおそらくハイエンドのバイトから開始することにより、適切な場所の近くから開始できます4*$desired_chars。しかし、それでもまったく別のものを使用するのが最善だと思います。
cutまだマルチバイト文字をサポートしていないことに注意してください。もしそうなら、あなたはすることができますcut -zc-1234 | tr -d '\0'。