วิธีการแทนที่กลุ่มที่ถูกจับเท่านั้น?


196

ฉันมีรหัส HTML ก่อนและหลังสตริง:

name="some_text_0_some_text"

ฉันต้องการแทนที่0ด้วยสิ่งที่ชอบ:!NEW_ID!

ดังนั้นฉันทำ regex ง่าย:

.*name="\w+(\d+)\w+".*

แต่ฉันไม่เห็นวิธีการแทนที่เฉพาะบล็อกที่ถูกจับ

มีวิธีในการแทนที่ผลการจับภาพเช่น ($ 1) โดยสายอื่น ๆ ?

ผลลัพธ์จะเป็น:

name="some_text_!NEW_ID!_some_text"

คำตอบ:


359

ทางออกคือการเพิ่มการจับภาพสำหรับข้อความก่อนหน้าและต่อไปนี้:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")

76
สวัสดีจากอนาคต! ทางออกของคุณดูเรียบร้อยจริงๆ คุณช่วยอธิบายคำตอบของคุณได้ไหม
Polyducks

21
วงเล็บถูกใช้เพื่อสร้าง "กลุ่ม" ซึ่งได้รับการกำหนดดัชนีฐาน 1 ซึ่งสามารถเข้าถึงได้ในการแทนที่ด้วย a $ดังนั้นคำแรก(\w+)อยู่ในกลุ่มและกลายเป็น$1ส่วนที่(\d+)อยู่ตรงกลางเป็นกลุ่มที่สอง (แต่ได้รับ ละเว้นในแทนที่) $3และกลุ่มที่สามคือ ดังนั้นเมื่อคุณให้สตริงการแทนที่"$1!new_ID!$3"$ 1 และ $ 3 จะถูกแทนที่โดยอัตโนมัติด้วยกลุ่มแรกและกลุ่มที่สามทำให้กลุ่มที่ 2 ถูกแทนที่ด้วยสตริงใหม่โดยรักษาข้อความไว้รอบ ๆ
mix3d

4
ในขณะที่ฉันเข้าใจว่ามันใช้งานได้อย่างไรฉันหวังว่าจะได้คำตอบที่สวยงามยิ่งขึ้น> <อย่างไรก็ตามฉันสามารถก้าวไปข้างหน้าด้วยโค้ดของฉันได้ทันที!
mix3d

9
1) คุณไม่จำเป็นต้องจับภาพ \ d + 2) ทำไมคุณถึงพูดว่ามันไม่สง่างาม? การถ่ายภาพมีไว้เพื่อเก็บสิ่งของไม่ทิ้งไป สิ่งที่คุณต้องการเก็บไว้คืออะไรคือ AROUND \ d + ดังนั้นมันจึงสมเหตุสมผล (และสง่างามพอ) ในการถ่ายภาพบริเวณโดยรอบเหล่านี้
Sir4ur0n

3
ทางออกที่ดี ถ้าเราต้องการแทนที่กลุ่มการดักจับโดยใช้กลุ่มการดักจับเป็นพื้นฐานสำหรับการแปลง มีวิธีการแก้ปัญหาที่สง่างามเท่ากันในการทำเช่นนี้? ขณะนี้ฉันจัดเก็บกลุ่มที่ถูกจับภาพไว้ในรายการ, วนพวกมันและแทนที่กลุ่มการจับภาพด้วยค่าที่ถูกเปลี่ยนในแต่ละการวนซ้ำ
sookie

15

ตอนนี้ Javascript มี lookbehind (ตั้งแต่ES2018 ) ในสภาพแวดล้อมที่ใหม่กว่าคุณสามารถหลีกเลี่ยงกลุ่มทั้งหมดในสถานการณ์เช่นนี้ แต่จงมองหาสิ่งที่เกิดขึ้นต่อหน้ากลุ่มที่คุณถูกจับและมองหาสิ่งที่ตามมาและแทนที่ด้วยเพียง !NEW_ID! :

const str = 'name="some_text_0_some_text"';
console.log(
  str.replace(/(?<=name="\w+)\d+(?=\w+")/, '!NEW_ID!')
);

ด้วยวิธีนี้การจับคู่แบบเต็มเป็นเพียงส่วนที่จำเป็นต้องเปลี่ยน

  • (?<=name="\w+)- Lookbehind for name"ตามด้วยอักขระคำ (โชคดีที่ lookbehinds ไม่จำเป็นต้องมีความกว้างคงที่ใน Javascript!)
  • \d+ - จับคู่หนึ่งหรือมากกว่าหนึ่งหลัก - ส่วนเดียวของรูปแบบที่ไม่ได้อยู่ใน lookaround ส่วนเดียวของสตริงที่จะอยู่ในการแข่งขันที่เกิดขึ้น
  • (?=\w+")- มองหาตัวอักษรของคำตามด้วย" `

โปรดทราบว่า lookbehind เป็นของใหม่สวย มันทำงานได้ในรุ่นที่ทันสมัยของ V8 (รวมทั้ง Chrome, Opera, และ Node) แต่ไม่ได้อยู่ในสภาพแวดล้อมอื่น ๆ มากที่สุดอย่างน้อยไม่ได้เลย ดังนั้นในขณะที่คุณสามารถใช้ lookbehind ใน Node และในเบราว์เซอร์ของคุณเอง (ถ้ามันทำงานบน V8 รุ่นใหม่) แต่ก็ยังไม่รองรับลูกค้าแบบสุ่ม (เช่นในเว็บไซต์สาธารณะ)


เพิ่งรันการทดสอบเวลาอย่างรวดเร็วและมันค่อนข้างน่าประทับใจว่าอินพุตมีความสำคัญอย่างไร: jsfiddle.net/60neyop5
Kaiido

แต่ถ้าเช่นฉันต้องการแยกจำนวนหลายตัวและ "นำกลับมา" ฉันจะต้องจัดกลุ่มด้วย\d+ใช่ไหม
Mosh Feu

@MoshFeu ใช้ฟังก์ชั่นและใช้ทดแทนการแข่งขันทั้งตัวเลข: match => match * 2เปลี่ยนพารามิเตอร์ที่สองด้วย ตัวเลขยังคงเป็นการแข่งขันทั้งหมดดังนั้นจึงไม่จำเป็นสำหรับกลุ่ม
CertainPerformance

เข้าใจแล้ว ขอบคุณ!
Mosh Feu

2

การปรับปรุงเล็กน้อยในคำตอบของ Matthew อาจเป็น lookahead แทนที่จะเป็นกลุ่มที่รวบรวมล่าสุด:

.replace(/(\w+)(\d+)(?=\w+)/, "$1!NEW_ID!");

หรือคุณสามารถแยกทศนิยมและเข้าร่วมกับรหัสใหม่ของคุณเช่นนี้:

.split(/\d+/).join("!NEW_ID!");

ตัวอย่าง / เกณฑ์มาตรฐานที่นี่: https://codepen.io/jogai/full/oyNXBX


1

ด้วยการจับสองกลุ่มก็จะเป็นไปได้เช่นกัน ฉันจะรวมเครื่องหมายขีดคั่นสองตัวเป็นขอบเขตซ้ายและขวาเพิ่มเติมก่อนและหลังตัวเลขและนิพจน์ที่ปรับเปลี่ยนจะมีลักษณะดังนี้:

(.*name=".+_)\d+(_[^"]+".*)

const regex = /(.*name=".+_)\d+(_[^"]+".*)/g;
const str = `some_data_before name="some_text_0_some_text" and then some_data after`;
const subst = `$1!NEW_ID!$2`;
const result = str.replace(regex, subst);
console.log(result);


หากคุณต้องการที่จะสำรวจ / ง่าย / แก้ไขการแสดงออกก็ถูกอธิบายในแผงด้านบนขวาของ regex101.com หากคุณต้องการคุณยังสามารถดูในลิงค์นี้ว่ามันจะตรงกับอินพุตตัวอย่างบางส่วนได้อย่างไร


วงจร RegEx

jex.imเห็นภาพการแสดงออกปกติ:

ป้อนคำอธิบายรูปภาพที่นี่


0

ตัวเลือกที่ง่ายกว่าคือเพียงแค่จับตัวเลขและแทนที่มัน

const name = 'preceding_text_0_following_text';
const matcher = /(\d+)/;

// Replace with whatever you would like
const newName = name.replace(matcher, 'NEW_STUFF');
console.log("Full replace", newName);

// Perform work on the match and replace using a function
// In this case increment it using an arrow function
const incrementedName = name.replace(matcher, (match) => ++match);
console.log("Increment", incrementedName);

ทรัพยากร

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