การจับคู่คำที่มี / ไม่มีช่องว่างต่อท้ายแตกต่างกันอย่างไร


12

ฉันกำลังเรียนรู้การเขียนสคริปต์เชลล์และฉันใช้ HackerRank อยู่ มีคำถามที่เกี่ยวข้องsedกับเว็บไซต์เดียวกันคือ: 'Sed' command # 1 :

สำหรับแต่ละบรรทัดในไฟล์อินพุตที่กำหนดให้แปลงคำแรก 'the' with 'this' การค้นหาและการแปลงควรคำนึงถึงขนาดตัวพิมพ์

ก่อนอื่นเลยฉันลอง

sed 's/the/this/'

แต่ในกรณีทดสอบตัวอย่างนั้นล้มเหลว จากนั้นฉันก็ลอง

sed 's/the /this /'

และมันก็ใช้งานได้ ดังนั้นคำถามเกิดขึ้นช่องว่างที่สร้างขึ้นต่างกันอย่างไร ฉันทำอะไรบางอย่างหายไปหรือเปล่า


ฉันถือว่ารุ่นแรกยัง "ทำงาน" แต่ไม่เหมือนที่คุณคาดหวัง มันควรจะแทนที่การเกิดขึ้นครั้งแรกของลำดับตัวอักษร "the" แต่คุณอาจมองไปที่การเกิดขึ้นครั้งแรกของคำว่า "the"
Dubu

ในเรื่องนี้ใช่ในทางปฏิบัติไม่
Rolf

คำตอบ:


7

ความแตกต่างคือว่ามีช่องว่างหลังจากtheในข้อความอินพุต
ตัวอย่างเช่น

ด้วยประโยคที่ไม่มีช่องว่างไม่มีการแทนที่:

$ echo 'theman' | sed 's/the /this /'
theman

ด้วยประโยคที่มีช่องว่างทำงานตามที่คาดไว้:

$ echo 'the man' | sed 's/the /this /'
this man

ด้วยประโยคที่มีอักขระช่องว่างอื่นจะไม่มีการแทนที่เกิดขึ้น:

$ echo -e 'the\tman' | sed 's/the /this /'
the     man

ฉันคิดถึงสิ่งนั้น ฉันต้องใช้ "the" เป็นสตริง ไม่ใช่ซับสตริง
JHA

1
@JHA: มันมีความสำคัญในตอนท้ายของบรรทัด เช่นคำว่า "the" อาจปรากฏที่ท้ายบรรทัดโดยเป็นส่วนหนึ่งของไฟล์ที่มีการตัดบรรทัด แต่ยังคงอยู่ในกึ่งกลางของย่อหน้าและยังคงเป็นคำปกติในประโยคภาษาอังกฤษ the( |$)อาจเข้าใกล้การทำงานหาก Extended regex นั้นใช้งานได้ อย่างไรก็ตาม IDK สิ่งที่คุณหมายถึง "เป็นสตริง" กับสตริงย่อย ในทั้งสองกรณีเป็นซับสตริงของทั้งบรรทัดและผลการทดสอบของคุณไม่เพียงพอที่จะตรวจพบกรณีที่"the "ล้มเหลว คำตอบของ Kusalanada นั้นดีกว่าฉันแนะนำให้ยอมรับ
Peter Cordes

20

มันเป็นวิธีที่ถูกและผิดพลาดในการดำเนินการจับคู่คำ

โปรดทราบว่าtheด้วยการเว้นวรรคหลังจากนั้นไม่ตรงกับคำtherebyดังนั้นการจับคู่กับช่องว่างหลังจากtheหลีกเลี่ยงการจับคู่สตริงนั้นในตอนเริ่มต้นของคำ แต่ก็ยังคงไม่ตรงกับbathe(ถ้าตามด้วยช่องว่าง) และมันไม่ได้ตรงกับtheที่ส่วนท้ายของบรรทัด

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

ให้ใช้รูปแบบขอบเขตคำที่มีความกว้างเป็นศูนย์แทน:

sed 's/\<the\>/this/'

\<และ\>ตรงกับขอบเขตก่อนและหลังคำเช่นช่องว่างระหว่างที่ตัวอักษรคำและอักขระที่ไม่ใช่คำ อักขระคำโดยทั่วไปคือการจับคู่อักขระใด ๆ[[:alnum:]_](หรือ[A-Za-z0-9_]ในภาษา POSIX)

ด้วย GNU sedคุณสามารถใช้\bแทน\<และ\>:

sed 's/\bthe\b/this/'

7

sed ทำงานด้วยการแสดงออกปกติ การใช้sed 's/the /this /'คุณเพียงแค่สร้างพื้นที่หลังจากtheส่วนหนึ่งของรูปแบบที่ตรงกัน

การใช้sed 's/the/this/'คุณจะแทนที่เหตุการณ์ทั้งหมดtheโดยthisไม่คำนึงว่าจะมีพื้นที่ว่างเหลืออยู่theหรือไม่

ในแบบฝึกหัด HackerRank ผลลัพธ์จะเหมือนกันเพราะการแทนที่ด้วยสิ่งนี้เป็นตรรกะ ... คุณแทนที่คำนามโปรซึ่งตามค่าเริ่มต้นจะตามด้วยช่องว่าง (กฎไวยากรณ์)

คุณสามารถเห็นความแตกต่างถ้าคุณลองตัวอย่างเพื่อใช้ประโยชน์theในคำว่าthe theater:

echo 'the theater' |sed 's/the /THE /g'
THE theater                              
#theater is ignored since the is not followed by space

echo 'the theater' |sed 's/the/THE/g'
THE THEater
#both the are capitalized.

ขอบคุณสำหรับคำตอบ ชื่นชม :)
JHA

"คุณแทนที่สิ่งที่เกิดขึ้นทั้งหมด"เพื่อให้ชัดเจน: หากไม่มีข้อความgหลังการแทนที่คุณจะแทนที่เฉพาะเหตุการณ์ที่เกิดขึ้นครั้งแรกเท่านั้น
Dubu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.