ฉันจะตัดทอนไฟล์ข้อความ (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"
เป็นวิธีหนึ่งในการส่งชื่อไฟล์ไปยัง gawk
RS='^$'
: โหมด Slurpด้วย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))"
แต่จะมีประสิทธิภาพน้อยลงเนื่องจากจะอ่านอินพุตและเขียนเอาต์พุตหนึ่งไบต์ในแต่ละครั้ง iconv
เป็นคำสั่งมาตรฐาน แต่ชื่อการเข้ารหัสไม่ได้มาตรฐานดังนั้นคุณอาจพบระบบที่ไม่มีUCS-4
ไม่ว่าในกรณีใด ๆ แม้ว่าผลลัพธ์จะมีความยาวไม่เกิน 1234 ตัวอักษร แต่ท้ายที่สุดอาจไม่ใช่ข้อความที่ถูกต้องเนื่องจากอาจสิ้นสุดในบรรทัดที่ไม่มีการคั่น
โปรดทราบว่าในขณะที่คำตอบเหล่านั้นจะไม่ตัดข้อความที่อยู่ตรงกลางของตัวละคร แต่พวกเขาสามารถแยกมันออกมากลางกราฟเช่นการé
แสดงเป็น U + 0065 U + 0301 ( e
ตามด้วยสำเนียงเฉียบพลันที่รวมกัน) หรืออังกูลพยางค์กราฟในรูปแบบที่ย่อยสลาย
¹และในการป้อนข้อมูลไปป์คุณไม่สามารถใช้bs
ค่าอื่นที่ไม่ใช่ 1 ได้อย่างน่าเชื่อถือเว้นแต่ว่าคุณจะใช้iflag=fullblock
ส่วนขยาย GNU เช่นเดียวกับที่dd
สามารถอ่านค่าสั้น ๆ หากมันอ่านไปป์เร็วกว่าiconv
เติม
dd bs=1234 count=4
หากคุณรู้ว่าไฟล์ข้อความมี Unicode เข้ารหัสเป็น UTF-8 คุณต้องถอดรหัส UTF-8 ก่อนเพื่อให้ได้ลำดับของเอนทิตีอักขระ Unicode และแยกออก
ฉันเลือก Python 3.x สำหรับงาน
กับงูหลาม 3.x ฟังก์ชั่นเปิด ()มีข้อโต้แย้งคำสำคัญเป็นพิเศษencoding=
สำหรับการอ่านข้อความไฟล์ คำอธิบายของวิธีการ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>
เรียกมันด้วย
การดำเนินการนี้จะลบอักขระตัวสุดท้ายออกทีละตัวจนกว่าจะบรรลุเป้าหมายซึ่งดูเหมือนว่าจะมีประสิทธิภาพที่แย่มากโดยเฉพาะไฟล์ที่ใหญ่กว่า ฉันแค่อยากจะนำเสนอสิ่งนี้เป็นความคิดที่จะแสดงความเป็นไปได้มากขึ้น
wc
นับรวมตามลำดับของ O (n ^ 2) ไบต์ทั้งหมดสำหรับเป้าหมายครึ่งทางลงในไฟล์ มันควรจะเป็นไปได้ที่จะค้นหาแบบไบนารีแทนการค้นหาเชิงเส้นโดยใช้ตัวแปรที่คุณเพิ่มหรือลดเช่น echo -n "${result::-$chop}" | wc -m
หรือบางสิ่งบางอย่าง (และในขณะที่คุณอยู่ที่มันให้ปลอดภัยแม้ว่าเนื้อหาไฟล์เริ่มต้นด้วย-e
หรือบางสิ่งบางอย่างอาจใช้printf
) แต่คุณยังคงไม่ชนะวิธีที่ดูอักขระอินพุตแต่ละครั้งเพียงครั้งเดียวดังนั้นอาจไม่คุ้มค่า
$result
จนถึงจนกว่าจะตรงกับความยาวที่ต้องการ แต่ถ้าความยาวที่ต้องการเป็นจำนวนสูงมันก็ไม่มีประสิทธิภาพ
$desired_chars
ไบต์ที่ต่ำสุดหรืออาจจะเป็น4*$desired_chars
ที่สูง แต่ถึงกระนั้นฉันคิดว่ามันเป็นการดีที่สุดที่จะใช้อย่างอื่นอย่างสมบูรณ์
cut
ยังคงไม่รองรับอักขระหลายไบต์cut -zc-1234 | tr -d '\0'
ถ้ามันไม่ได้คุณสามารถทำ