ฉันจะแทรกช่องว่างทุกสี่อักขระในบรรทัดยาวได้อย่างไร


30

ฉันมีเส้นยาวที่ฉันต้องการแทรกช่องว่างทุก ๆ 4 ตัวอักษรในข้อความทึบเส้นเดียวเพื่อให้อ่านง่ายขึ้นวิธีที่ง่ายที่สุดในการทำเช่นนี้คืออะไร? นอกจากนี้ฉันควรจะสามารถป้อนบรรทัดจากท่อ เช่น

echo "foobarbazblargblurg" | <some command here>

จะช่วยให้

foob arba zbla rgbl urg

คำตอบ:


54

ใช้ sed ดังนี้:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg

1
การสาปแช่งที่อยู่ใกล้กับsedฉันพยายามก่อนฉันจะเตะตัวเอง
xenoterracide

7
แค่อยากรู้อยากเห็นสิ่งที่ '&' สำเร็จ โอ้มันเป็นมาตรฐานสำหรับ 'สิ่งที่เข้าคู่กัน' โง่ฉัน
Omnifarious

1
ควรสังเกตว่าสิ่งนี้จะเพิ่มช่องว่างที่ส่วนท้ายเช่นกันหากมีอักขระอีกหนึ่งตัวในสตริงซึ่งอาจไม่เป็นที่ต้องการ
Anubis

@Anubis's/.\{4\}/& /g;s/ $//'
wieczorek1990

20

คุณสามารถใช้ตัวอย่างง่ายๆดังต่อไปนี้:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl

เยี่ยมมาก ... ฉันคิดว่ามันดีกว่าsedคำตอบ ฉันไม่เคยรู้จักfoldมาก่อน
Wildcard

1
น่าเสียดายที่ GNU รุ่นปัจจุบันใช้foldงานไม่ได้กับอักขระหลายไบต์ (เช่นเดียวกับecho €€€€€€€€ | fold -w4 | paste -sd' ' -ใน UTF-8)
Stéphane Chazelas

3

นี่คือตัวอย่างการใช้grepและxargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl

xargsทำงานechoตามค่าเริ่มต้นดังนั้นมันจะไม่ทำงานกับคำเช่น-nenหรือที่มีแบ็กสแลชขึ้นอยู่กับการechoใช้งาน คุณจะเห็นอักขระขึ้นบรรทัดใหม่แปลก ๆ ซักครั้งและ xargs ทำงานมากกว่าหนึ่งechoตัว ดีกว่าไปป์paste -sd ' ' -แทน โปรดทราบว่า-oไม่ใช่ตัวเลือกมาตรฐาน
Stéphane Chazelas

3

ใน bash เท่านั้นไม่มีคำสั่งภายนอก:

str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"

หรือเป็นเวอร์ชันไพพ์แบบบรรทัดเดียว:

echo foobarbazblargblurg | 
  { IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }

วิธีการทำงานนี้คือการแปลงอักขระแต่ละตัวของสตริงให้เป็น "(.)" สำหรับการจับคู่และจับภาพด้วย regex =~จากนั้นเพียงแค่ส่งออกนิพจน์ที่จับจาก BASH_REMATCH[]อาร์เรย์จัดกลุ่มตามที่ต้องการ ช่องว่างนำหน้า / ท้าย / กลางถูกรักษาไว้ให้ลบเครื่องหมายคำพูดรอบ ๆ"${BASH_REMATCH[@]:1}"เพื่อละเว้น

ที่นี่มันถูกรวมไว้ในฟังก์ชั่นอันนี้จะประมวลผลข้อโต้แย้งหรืออ่าน stdin หากไม่มีข้อโต้แย้ง:

function fmt4() {
  while IFS= read -r str; do
    [[ $str =~ ${str//?/(.)} ]]
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
  done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}

$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg 

คุณสามารถกำหนดพารามิเตอร์จำนวนเพื่อปรับรูปแบบสตริงได้อย่างง่ายดาย

เพิ่มช่องว่างต่อท้ายใช้สองprintfs แทนหนึ่งถ้าเป็นปัญหา:

printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"

ครั้งแรก printfพิมพ์ (สูงสุด) 4 ตัวอักษรตัวแรกที่สองตามเงื่อนไขพิมพ์ส่วนที่เหลือทั้งหมด (ถ้ามี) ด้วยพื้นที่ชั้นนำเพื่อแยกกลุ่ม การทดสอบมีไว้สำหรับ 5 องค์ประกอบที่ไม่ใช่ 4 เพื่ออธิบายองค์ประกอบของศูนย์

หมายเหตุ:

  • เปลือกprintf's %cสามารถนำมาใช้แทน%s, %c(อาจจะ) ทำให้ความตั้งใจที่ชัดเจน แต่ก็ไม่ได้หลายไบต์ปลอดภัยของตัวละคร หากเวอร์ชันของ bash ของคุณมีความสามารถดังกล่าวข้างต้นจะปลอดภัยทุกตัวอักษรหลายไบต์
  • เชลล์printfนำสตริงรูปแบบของมันกลับมาใช้ใหม่จนกว่ามันจะหมดข้อโต้แย้งดังนั้นมันจึงกลืนกิน 4 อาร์กิวเมนต์ในแต่ละครั้งและจัดการกับอาร์กิวเมนต์ที่ต่อท้าย (ดังนั้นไม่จำเป็นต้องใช้เคสที่มีขอบซึ่งแตกต่างจากคำตอบอื่น ๆ
  • BASH_REMATCH[0] เป็นสตริงที่ตรงกันทั้งหมดดังนั้นเอาต์พุตเริ่มต้นจากดัชนี 1 เท่านั้น
  • ใช้printf -v myvar ...แทนเพื่อจัดเก็บกับตัวแปรmyvar(ขึ้นอยู่กับพฤติกรรมการอ่านลูป / subshell ปกติ)
  • เพิ่มprintf "\n"ถ้าจำเป็น

คุณสามารถทำให้การทำงานข้างต้นในzshถ้าคุณใช้อาร์เรย์match[]แทนBASH_REMATCH[]และลบ 1 จากดัชนีทั้งหมดที่zshไม่ได้เก็บองค์ประกอบ 0 กับการแข่งขันทั้งหมด


3

มีzshเพียง:

str=foobarbazblargblurg

set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }

หรือ

printf '%s%s%s%s ' ${(s::)str}

มีksh93เพียง:

printf '%s\n' "${str//????/\0 }"

ด้วย POSIX เชลล์ใด ๆ เท่านั้น (เช่นเดียวกับการหลีกเลี่ยงพื้นที่ต่อท้ายหากความยาวอินพุตเป็นทวีคูณของ 4):

out=
while true; do
  case $str in
    (?????*)
      new_str=${str#????}
      out=$out${str%"$new_str"}' '
      str=$new_str
      ;;
    (*)
      out=$out$str
      break
  esac
done
printf '%s\n' "$out"

ตอนนี้ที่สำหรับตัวละคร หากคุณต้องการที่จะทำมันบนกลุ่มกราฟ (ตัวอย่างเช่นการทำลายStéphaneเขียน$'Ste\u0301phane'เป็นStép haneและไม่Ste phan e) ด้วยzsh:

set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
  out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out

ด้วย ksh93 คุณสามารถแยกตามความกว้างของหน้าจอได้เช่นกันซึ่งสามารถใช้ได้กับสิ่งที่กล่าวมาStéphaneข้างต้น แต่อาจช่วยได้เมื่อเกี่ยวข้องกับอักขระที่มีความกว้างเป็นศูนย์หรือความกว้างสองเท่าบางประเภท:

str=$'Ste\u301phane' out=
while
  start=${ printf %L.4s. "$str"; }
  start=${start%.}
  [ "$start" != "$str" ]
do
  out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"

2

ฉันจะตอบด้วยการแทรกช่องว่างตามที่ต้องการเพื่อให้มีพื้นที่ว่างปรากฏขึ้นอย่างน้อยทุก ๆ 4 อักขระในหนึ่งบรรทัด ไม่แน่ใจว่าคุณต้องการจัดการกรณีนี้ในลักษณะใด ตัวอย่างเช่นหากได้รับอินพุตของ "aa bbccdd" คุณจะได้รับเอาต์พุต "aa bbcc dd" แทนที่จะเป็น "aa b bccd d"

ฉันใช้ Perl สำหรับ lookahead แต่ฉันไม่ค่อยคุ้นเคยกับ Perl โดยทั่วไปดังนั้นอาจต้องมีการปรับแต่ง:

$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg

$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!

$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some  inp ut'!

$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' | 
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)

0

ฉันทำสิ่งนี้โดยใช้ python

ก่อนอื่นฉันอ่านไฟล์จากนั้นฉันก็หารด้วย 4 ตัวอักษรและเพิ่มช่องว่าง

#!/usr/bin/python
import re
b=re.compile(r'[a-z]{4}')

p=open('/root/l.txt','r')
i=p.readlines()
for j in i:
    m=re.findall(b,j)
print " " .join (m) + "  "

/root/l.txt ==> ประกอบด้วยเนื้อหาที่คุณให้ไว้ในตัวอย่าง

เอาท์พุต

foob arba zbla rgbl
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.