(UTF-8로 인코딩된) 텍스트 파일을 주어진 문자 수로 자르는 방법은 무엇입니까? 줄 길이는 상관없구요, 단어 중간에 컷이 있어도 됩니다.
cut
한 줄씩 작업하는 것 같지만 완전한 파일을 원합니다.head -c
문자가 아닌 바이트를 사용하십시오.
답변1
일부 시스템에는 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
GNU를 사용하면 sed
다음과 같이 할 수 있습니다. (파일에 NUL 문자나 유효한 문자를 형성하지 않는 바이트 시퀀스가 포함되어 있지 않다고 가정할 때 - 두 가지 모두 텍스트 파일에 해당되어야 합니다.)
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
그러나 이는 파일 전체를 읽고 메모리에 저장한 다음 새 복사본을 쓰기 때문에 훨씬 덜 효율적입니다.
GNU awk
GNU와 동일 awk
:
awk -i /usr/share/awk/inplace.awk -v RS='^$' -e '
{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-e code -E /dev/null "$file"
임의의 파일 이름을 전달하는 방법입니다.gawk
RS='^$'
:흡연 모드.
사용하지 마세요-i inplace
현재 작업 디렉터리(as or)에서 확장 기능을 먼저 gawk
로드 하려고 하면 누군가가 해당 디렉터리에 악성 코드를 심었을 수 있습니다. 시스템과 함께 제공되는 확장 프로그램 의 경로 는 다를 수 있습니다. 출력을 참조하세요.inplace
inplace
inplace.awk
inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
쉘 내장 함수
ksh93
, bash
또는 사용 ( 내용에 NUL 바이트가 포함되어 있지 않다고 가정하고 zsh
Except 이외의 셸 사용 ):zsh
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"
아이콘 + 헤더
도착하다인쇄UTF32BE
처음 1234자의 경우 / 와 같이 문자당 고정된 바이트 수를 사용하는 인코딩으로 변환하는 것이 또 다른 옵션일 수 있습니다 UCS-4
.
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c
표준은 아니지만 꽤 일반적입니다. 표준에 해당하는 것은 dd bs=1 count="$((1234 * 4))"
한 번에 1바이트를 읽고 한 번에 1바이트를 쓰기 때문에 효율성이 떨어집니다. iconv
표준 명령이지만 인코딩 이름은 표준화되어 있지 않으므로 시스템이 그렇지 않을 수도 있습니다.UCS-4
노트
어떤 경우든 출력은 최대 1234자까지 가능하지만 구분되지 않은 줄로 끝날 수 있으므로 유효한 텍스트가 아닐 수도 있습니다.
또한 이러한 솔루션은 문자 중간에 있는 텍스트를 자르지 않지만 문자 중간에 있는 텍스트를 깨뜨릴 수 있습니다.문자소, 예를 들어 é
U+0065 U+0301(a e
다음에 날카로운 악센트 결합) 또는 분해된 형태의 한국어 음절 문자소로 표현됩니다.
bs
1 및 파이프 입력에서는 GNU 확장을 사용하지 않는 한 1 이외의 값을 안정적으로 사용할 수 없습니다. 파이프를 채울 수 있는 것보다 파이프를 더 빨리 읽을 수 있으면 짧은 읽기가 가능하기 iflag=fullblock
때문입니다.dd
iconv
답변2
텍스트 파일에 UTF-8로 인코딩된 유니코드가 포함되어 있다는 것을 알고 있는 경우 먼저 UTF-8을 디코딩하여 유니코드 문자 엔터티 시퀀스를 얻고 이를 분할해야 합니다.
나는 이 작업을 위해 Python 3.x를 선택하겠습니다.
Python 3.x 함수 사용열려 있는()encoding=
읽기를 위한 추가 키워드 인수가 있습니다.텍스트 파일. 방법 설명io.TextIOBase.read()유망해 보입니다.
따라서 Python 3을 사용하면 다음과 같습니다.
truncated = open('/path/to/file.txt', 'rt', encoding='utf-8').read(1000)
분명히 실제 도구에는 명령줄 매개변수, 오류 처리 등이 추가됩니다.
Python 2.x를 사용하면 자신만의 파일류 객체를 구현하고 입력 파일을 한 줄씩 디코딩할 수 있습니다.
답변3
사용행복하다(이전의 Perl6)
Raku는 유니코드에 대한 고급 내장 지원을 제공합니다. 파일 핸들 이름을 제외하고 문자소는 유니코드 컨소시엄의 이름으로 변환됩니다.표준화된 형태 C"(NFC)가 기본으로 설정되어 있습니다. 아래는 이모티콘 예시입니다.
입력 예:
~$ raku -e 'for (0..8) -> $i { $_.[0..$i].join.put given "\x1F600".."\x1F64F"};' > emoticons_0-to-8.txt
~$ cat emoticons_0-to-8.txt
답변4
다른 방법을 추가하고 싶습니다. 아마도 최고의 성능을 발휘하지는 못하고 길지만 이해하기 쉽습니다.
#!/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>
.
이는 목표에 도달할 때까지 마지막 문자를 하나씩 제거하는데, 이는 특히 대용량 파일의 경우 성능 측면에서 매우 나쁜 것 같습니다. 저는 단지 이것을 더 많은 가능성을 보여주기 위한 아이디어로 제시하고 싶었을 뿐입니다.