如何将(UTF-8 编码)文本文件截断为给定数量的字符?我不在乎行的长度,而且切口可以在字的中间。
cut
似乎在线操作,但我想要一个完整的文件。head -c
使用字节,而不是字符。Sté*_*las 14
某些系统具有truncate
将文件截断为多个字节(而非字符)的命令。
我不知道任何截断为多个字符的字符,尽管您可以求助于perl
大多数系统上默认安装的字符:
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
Run Code Online (Sandbox Code Playgroud)
使用-Mopen=locale
,我们使用语言环境的字符是什么概念(因此在使用 UTF-8 字符集的语言环境中,这是 UTF-8 编码的字符)。-CS
如果您希望 I/O 以 UTF-8 进行解码/编码,而不管区域设置的字符集如何,请替换为。
$/ = \1234
:我们将记录分隔符设置为对整数的引用,这是一种指定固定长度(字符数)记录的方法。
然后在读取第一条记录时,我们就地截断 stdin(所以在第一条记录的末尾)并退出。
使用 GNU sed
,您可以这样做(假设文件不包含 NUL 字符或不构成有效字符的字节序列——这两者都应该适用于文本文件):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
Run Code Online (Sandbox Code Playgroud)
但这效率要低得多,因为它会完整读取文件并将其整个存储在内存中,然后写入一个新副本。
与 GNU 相同awk
:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
Run Code Online (Sandbox Code Playgroud)
-e code -E /dev/null "$file"
是将任意文件名传递给的一种方式 gawk
RS='^$'
:啜饮模式。使用ksh93
,bash
或zsh
(使用除 之外的外壳zsh
,假设内容不包含 NUL 字节):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
Run Code Online (Sandbox Code Playgroud)
与zsh
:
read -k1234 -u0 s < $file &&
printf %s $s > $file
Run Code Online (Sandbox Code Playgroud)
或者:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
Run Code Online (Sandbox Code Playgroud)
使用ksh93
or bash
(当心它在多个版本的多字节字符中是伪造的bash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
Run Code Online (Sandbox Code Playgroud)
ksh93
也可以原地截断文件,而不是用它的<>;
重定向操作符重写它:
IFS= read -rN1234 0<>; "$file"
Run Code Online (Sandbox Code Playgroud)
要打印前 1234 个字符,另一种选择是转换为每个字符具有固定字节数的编码,例如UTF32BE
/ UCS-4
:
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
Run Code Online (Sandbox Code Playgroud)
head -c
不是标准的,但相当普遍。标准等价物将是dd bs=1 count="$((1234 * 4))"
但效率较低,因为它会读取输入并一次写入一个字节¹。iconv
是标准命令,但编码名称未标准化,因此您可能会发现系统没有UCS-4
在任何情况下,虽然输出最多有 1234 个字符,但它最终可能不是有效文本,因为它可能以非分隔行结尾。
同时还要注意,而这些解决方案将不能在字符的中间切开文字,他们就能把它在中间字形,像一个é
表示为U + 0065 U + 0301(一个e
接着一个组合重音符)或分解形式的韩文音节字素。
¹ 并且在管道输入上,bs
除非您使用iflag=fullblock
GNU 扩展,否则您不能可靠地使用 1 以外的值,因为dd
如果读取管道比iconv
填充管道快,则可以进行短读取
如果您知道文本文件包含编码为 UTF-8 的 Unicode,您必须首先解码 UTF-8 以获得一系列 Unicode 字符实体并拆分它们。
我会选择 Python 3.x 来完成这项工作。
在 Python 3.x 中,函数open()有一个额外的关键字参数encoding=
用于读取文本文件。io.TextIOBase.read()方法的描述看起来很有希望。
所以使用 Python 3 它看起来像这样:
truncated = open('/path/to/file.txt', 'rt', encoding='utf-8').read(1000)
Run Code Online (Sandbox Code Playgroud)
显然,真正的工具会添加命令行参数、错误处理等。
使用 Python 2.x,您可以实现自己的类文件对象并逐行解码输入文件。