ใน `sed` ฉันจะใส่“ &” หนึ่งตัวระหว่างอักขระในสตริงได้อย่างไร


คำตอบ:


25

ด้วย GNU sed:

sed 's/./\&&/2g'

( substituteทุก ( g) ตัวอักษร ( .) แบบเดียวกับที่ ( &) นำหน้าด้วย&( \&) แต่เพียงเริ่มต้นจากการเกิดที่สอง ( 2))

portably:

sed 's/./\&&/g;s/&//'

(แทนที่ทุกครั้งที่เกิดขึ้น แต่จากนั้นลบรายการแรก&ที่เราไม่ต้องการ)

ด้วยawkการใช้งานบางอย่าง(ไม่ใช่ POSIX เนื่องจากลักษณะการทำงานไม่ได้ระบุไว้สำหรับ FS ที่ว่างเปล่า):

awk -F '' -v OFS="&" '{$1=$1;print}'

(ที่มีgawkและอื่น ๆ ไม่กี่awkการใช้งานคั่นสนามว่างแยกบันทึกลงเป็นคนละตัวอักษร . the คั่นฟิลด์เอาท์พุท ( OFS) ตั้ง&. เรากำหนดค่าให้$1(ตัวเอง) เพื่อบังคับให้บันทึกที่จะสร้างใหม่ที่มีตัวคั่นเขตข้อมูลใหม่ ก่อนที่จะพิมพ์NF=NFยังใช้งานได้และมีประสิทธิภาพมากขึ้นเล็กน้อยในการใช้งาน awk จำนวนมาก แต่พฤติกรรมเมื่อคุณทำเช่นนั้นในขณะนี้ยังไม่ได้ระบุโดย POSIX)

perl:

perl -F -lape '$_=join"&",@F' 

( -peรันโค้ดสำหรับทุกบรรทัดและพิมพ์ผล ( $_); -lแถบและใหม่เพิ่มปลายสายโดยอัตโนมัติ-apopulates @Fกับแยกข้อมูลเกี่ยวกับชุดที่คั่นใน-F. ซึ่งที่นี่เป็นสตริงว่างผลที่ได้คือการแยกตัวละครทุกตัวเข้า@F, จากนั้นเข้าร่วมกับพวกเขาด้วย '&' และพิมพ์บรรทัด)

อีกวิธีหนึ่งคือ:

perl -pe 's/(?<=.)./&$&/g' 

(แทนที่ตัวละครทุกตัวหากมีตัวละครอื่นนำหน้า (โอเปอเรเตอร์ regexp แบบมองหลัง (? <= ... ))

การใช้zshตัวดำเนินการเชลล์:

in=12345
out=${(j:&:)${(s::)in}}

(อีกครั้งแบ่งในตัวคั่นฟิลด์ว่างโดยใช้การตั้งs::ค่าสถานะการขยายพารามิเตอร์และเข้าร่วมกับ&)

หรือ:

out=${in///&} out=${out#?}

(แทนที่ทุกสิ่งที่เกิดขึ้น (ก่อนหน้าตัวละครทุกตัว) ด้วยการ&ใช้${var//pattern/replacement}โอเปอเรเตอร์ ksh (แม้ว่าในkshรูปแบบที่ว่างเปล่าหมายถึงอย่างอื่น แต่อย่างอื่นฉันไม่แน่ใจว่ามีอะไรอยู่bash) และลบอันแรกด้วยการ${var#pattern}ลอกPOSIX ผู้ประกอบการ)

การใช้ksh93ตัวดำเนินการเชลล์:

in=12345
out=${in//~(P:.(?=.))/\0&}

( ~(P:perl-like-RE)เป็นตัวดำเนินการ ksh93 glob เพื่อใช้นิพจน์ทั่วไปที่เหมือน perl (แตกต่างจาก perl's หรือ PCRE's แม้ว่า) (?=.)เป็นโอเปอเรเตอร์ที่ดูล่วงหน้า: แทนที่อักขระที่ระบุหากตามด้วยอักขระอื่นด้วยตัวเอง ( \0) และ&)

หรือ:

out=${in//?/&\0}; out=${out#?}

(แทนที่ตัวละครทุกตัว ( ?) ด้วย&และตัวของมันเอง ( \0) และเราลบอันยิ่งใหญ่ออก)

การใช้bashตัวดำเนินการเชลล์:

shopt -s extglob
in=12345
out=${in//@()/&}; out=${out#?}

(เช่นเดียวกับzsh's ยกเว้นว่าคุณจำเป็นต้อง@()มี (ผู้ประกอบการ ksh glob ที่คุณต้องการextglobในbash))


2
@AFSHIN ที่จะไม่ทำงานกับ012345ข้อมูล
Stéphane Chazelas

1
สิ่งนี้น่าจะใช้ได้awk -F '' -v OFS="&" 'NF=NF'
αғsнιη

1
@AFSHIN แต่ลบบรรทัดว่าง โดยทั่วไปเมื่อใช้การกระทำเป็นเงื่อนไขและตั้งใจผลลัพธ์ของการกระทำที่จะพิมพ์คุณต้องตรวจสอบให้แน่ใจว่าค่าที่ส่งคืนโดยการกระทำนั้นไม่ใช่สตริงว่างเปล่าหรือสตริงตัวเลขที่เปลี่ยนเป็น 0
Stéphane Chazelas

1
คุณสามารถเพิ่มคำอธิบายสั้น ๆ เกี่ยวกับวิธีการทำงานแต่ละอย่างได้หรือไม่ ดูเหมือนว่ามีบางสิ่งที่ยอดเยี่ยมที่จะเรียนรู้ที่นี่ แต่ฉันไม่รู้ด้วยซ้ำว่าฉันจะเริ่มค้นคว้าข้อมูลส่วนใหญ่อย่างไรเพื่อดูวิธีการใช้งานนอกขอบเขตของปัญหาเฉพาะนี้
IMSoP

1
@ StéphaneChazelas Brilliant ขอบคุณ การค้นหาเอกสารที่ซับซ้อนสำหรับสิ่งต่าง ๆ เช่น sed เป็นบิตของงานศิลปะดังนั้นการมีตัวอย่างบางส่วนเป็นวิธีที่ดีในการเรียนรู้บิตใหม่ที่คุณไม่เคยเห็นมาก่อน
IMSoP

15

ยูทิลิตี้ Unix:

fold -w1|paste -sd\& -

อธิบาย:

"fold -w1" - จะตัดอักขระอินพุตแต่ละบรรทัดเข้ากับบรรทัดของตัวเอง

พับ - ตัดแต่ละบรรทัดอินพุตให้พอดีกับความกว้างที่ระบุ

-w, - width = WIDTH ใช้คอลัมน์ WIDTH แทนที่จะเป็น 80

%echo 12345|fold -w1
1
2
3
4
5

"paste -sd\& -"- จะรวมบรรทัดอินพุตเข้าด้วยกันโดยใช้&เป็นตัวคั่น

วาง - ผสานเส้นของไฟล์

-s, - อนุกรมวางครั้งละหนึ่งไฟล์แทนที่จะเป็นแบบขนาน

-d, --delimiters = LIST ใช้อักขระซ้ำจาก LIST แทน TAB

%fold -w1|paste -sd\& -
1&2&3&4&5

(โปรดทราบว่าหากการป้อนข้อมูลมีหลายบรรทัดพวกเขาจะเข้าร่วมด้วย&)


2
ล้มเหลวในอักขระหลายไบต์ ลองecho "abcdeéèfg" | fold -1 | paste -sd\& -
ไอแซค

3
@Arrow ส่วนใหญ่อาจคุณเป็นเพียงการใช้รถ coreutilsรุ่นเท่าซึ่งไม่ได้มีการสนับสนุน Unicode เต็มรูปแบบ BSD พับแกน coreutils RedHat แพทช์(เช่น Fedora หรือ CentOS) เช่นเดียวกับการดำเนินการ BusyBox ของมันสามารถจัดการ Unicode ได้ดี
เรือเหาะ

5
sedคำถามคือเฉพาะที่เกี่ยวกับ
Alexander

6
@Alexander - นั่นเป็นความจริงและมีsedคำตอบที่ดีอยู่ด้านล่าง และฉันไม่เห็นอันตรายใด ๆ ในการสาธิตวิธีแก้ไขงานด้วยวิธีอื่น
เรือเหาะ

@ StéphaneChazelas> POSIXly คุณต้องการ fold -w 1 True ฉันได้เพิ่ม"-w"ขอบคุณ! "-", ในทางกลับกัน, ไม่จำเป็นต้องใช้ If no file operands are specified, the standard input shall be used
zeppelin


9
sed 's/\B/\&/g'

\ B - ตรงกันทุกที่ แต่อยู่ในขอบเขตของคำ; นั่นคือมันตรงกับถ้าตัวละครทางด้านซ้ายและตัวอักษรทางด้านขวามีทั้งตัวอักษร "คำ" หรือตัวละครทั้งที่ไม่ใช่คำ

ข้อมูล: GNU sed คู่มือส่วนขยายแสดงออกปกติ

การทดสอบ:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5

5
แนวคิดที่น่าสนใจ แต่คำถามไม่ได้บอกว่าสตริงไม่มีช่องว่างจุดหรืออะไรก็ตามที่อาจเป็นขอบเขตของคำ มันแค่บอกว่า "ระหว่างตัวละคร" ซึ่งควรตีความว่าเป็น "ตัวละครใด ๆ "
xhienne


4

นี่คือวิธีอื่น ส่วนแรกของการแสดงออกที่น่าดึงดูดใจจับตัวละครทุกตัวแล้วแทนที่ด้วยตัวละครและเครื่องหมายและ ส่วนที่สองจะลบเครื่องหมายและจากจุดสิ้นสุดของบรรทัด

echo 12345 | sed -r 's/(.)/\1\&/g;s/\&$//g'
1&2&3&4&5

ใช้งานได้กับอักขระหลายไบต์เช่นกัน


1
ไม่จำเป็นต้องโทรsedสองครั้งsedสคริปต์อาจมีหลายคำสั่ง:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

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