Як замінити лише захоплені групи?


196

Я маю HTML-код до і після рядка:

name="some_text_0_some_text"

Я хотів би замінити 0щось на кшталт:!NEW_ID!

Тому я зробив простий регулярний вираз:

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

Але я не бачу, як замінити виключно захоплений блок.

Чи є спосіб замінити захоплений результат на зразок ($ 1) на якийсь інший рядок?

Результатом буде:

name="some_text_!NEW_ID!_some_text"

Відповіді:


359

Рішення полягає в додаванні фіксацій для попереднього та наступного тексту:

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

76
Вітаємо з майбутнім! Ваше рішення виглядає дійсно акуратно. Не могли б ви пояснити свою відповідь?
Полідуки

21
Дужки використовуються для створення "груп", яким потім присвоюється індекс базової-1, доступний в заміну на a $, тому перше слово (\w+)знаходиться в групі і стає $1, середня частина (\d+)- другою групою, (але отримує ігнорується заміною), а третя група - $3. Отже, коли ви даєте рядок заміни "$1!new_ID!$3"$ 1 і 3 $ автоматично замінюються першою групою та третьою групою, дозволяючи 2-й групі замінити нову рядок, зберігаючи текст, що її оточує.
mix3d

4
Коли я розумію, як це працює, я сподівався на більш елегантне рішення>. <Тим не менш, я можу рухатися вперед зі своїм кодом зараз!
mix3d

9
1) Вам навіть не потрібно знімати \ d + 2) Чому ви кажете, що це не елегантно? Захоплення покликане тримати речі, а не викидати їх. Що ви хочете зберегти, це те, що ВИНАГО \ d +, тому це дійсно має сенс (і є досить елегантним), щоб захопити ці навколишні частини.
Sir4ur0n

3
Приємне рішення. Що робити, якщо ми хочемо замінити групи захоплення, використовуючи групу захоплення як основу для перетворення? Чи є настільки ж елегантне рішення для цього? В даний час я зберігаю захоплені групи у списку,
циклірую їх та замінюю

15

Тепер, коли Javascript дивиться назад (як на ES2018 ), у нових середовищах ви можете уникати груп повністю в таких ситуаціях. Швидше, дивіться за тим, що відбувається перед групою, яку ви захоплювали, і шукайте шукати, і замініть просто !NEW_ID! :

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

При цьому методі повна відповідність - це лише та частина, яку потрібно замінити.

  • (?<=name="\w+)- Lookbehind name", за яким слід слова символів (на щастя, lookbehinds не повинні фіксувати ширину в Javascript!)
  • \d+ - Збіг однієї чи кількох цифр - єдина частина шаблону, що не знаходиться навколо, єдина частина рядка, яка буде в отриманому збігу
  • (?=\w+")- Шукати символів слова з наступним символом " `

Майте на увазі, що погляд позаду досить новий. Він працює в сучасних версіях V8 (включаючи Chrome, Opera та Node), але не в більшості інших середовищ , принаймні, поки що. Отже, хоча ви можете надійно використовувати перспективу в Node та у власному браузері (якщо він працює на сучасній версії V8), він ще недостатньо підтримується випадковими клієнтами (наприклад, на загальнодоступному веб-сайті).


Щойно пройшов тест на швидкий термін, і це дуже вражає те, як важливий вхід: jsfiddle.net/60neyop5
Kaiido

Але якщо, наприклад, я хочу витягнути число, кратне і «поставити його назад», мені доведеться також групуватися \d+ , правда?
Мош Феу

@MoshFeu Використовуйте функцію заміщення та використовуйте всю відповідність, цифри: замініть другий параметр на match => match * 2 . Цифри залишаються цілим матчем, тому для груп немає потреби
CertainPerformance

Зробив тебе. Дякую!
Мош Феу

2

Невелике вдосконалення відповіді Метью могло б стати головою замість останньої групи захоплення:

.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 Circuit

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);

Ресурси

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.