Як отримати підрядок " It's big \"problem "
за допомогою регулярного виразу?
s = ' function(){ return " It\'s big \"problem "; }';
Як отримати підрядок " It's big \"problem "
за допомогою регулярного виразу?
s = ' function(){ return " It\'s big \"problem "; }';
Відповіді:
/"(?:[^"\\]|\\.)*"/
Працює в тренері Regex та Workstach PCRE.
Приклад тесту в JavaScript:
var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
var m = s.match(/"(?:[^"\\]|\\.)*"/);
if (m != null)
alert(m);
(?:...)
- це пасивна або не захоплююча група. Це означає, що пізніше його не можна буде повернути.
/(["'])(?:[^\1\\]|\\.)*?\1/
var s = ' my \\"new\\" string and \"this should be matched\"';
, такий підхід призведе до несподіваних результатів.
Цей похід походить від nanorc.sample, доступного у багатьох дистрибутивах Linux. Він використовується для підсвічування синтаксису рядків у стилі C
\"(\\.|[^\"])*\"
var s = ' my \\"new\\" string and \"this should be matched\"';
, такий підхід призведе до несподіваних результатів.
" \"(\\\\.|[^\\\"])*\" "
Як надає ePharaoh, відповідь така
/"([^"\\]*(\\.[^"\\]*)*)"/
Щоб вищезазначене було застосовано або до рядків з цитатами, або з цитатами з подвійним цитуванням, використовуйте
/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/
Більшість запропонованих тут рішень використовують альтернативні шляхи повторення, тобто (A | B) *.
Ви можете зіткнутися із переповненням стеків на великих входах, оскільки деякий компілятор шаблонів реалізує це за допомогою рекурсії.
Наприклад, Java: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993
Приблизно так:
"(?:[^"\\]*(?:\\.)?)*"
або той, який надав Гай Бедфорд, зменшить кількість кроків розбору, уникаючи більшості переливів стека.
/"(?:[^"\\]++|\\.)*+"/
Знято прямо з man perlre
системи Linux із встановленим Perl 5.22.0. Як оптимізація, цей регулярний вираз використовує "посесивну" форму обох +
і *
для запобігання зворотного відстеження, оскільки заздалегідь відомо, що рядок без завершальної лапки не збігається ні в якому разі.
/(["\']).*?(?<!\\)(\\\\)*\1/is
має працювати з будь-яким цитованим рядком
Цей ідеально працює на PCRE і не підпадає під StackOverflow.
"(.*?[^\\])??((\\\\)+)?+"
Пояснення:
"
;.*?
{Lazy match}; закінчується символом без втечі [^\\]
;(.*?[^\\])??
"
), але їй може передувати парна кількість знаків втечі (\\\\)+
; і це жадібний (!) необов'язковий: ((\\\\)+)?+
{Жадібний збіг}, тому що рядок може бути порожнім або без закінчення пар!"(.*?[^\\])?(\\\\)*"
ось один, який працює і з "і", і ви легко додаєте інших на початку.
("| ') (?: \\\ 1 | [^ \ 1]) *? \ 1
він використовує зворотну референцію (\ 1), яка відповідає точці, що є в першій групі ("або").
[^\1]
слід замінити, .
оскільки не існує такого поняття, як анти-зворотний посилання, і це все одно не має значення. Перша умова завжди буде відповідати, перш ніж може статися щось погане.
[^\1]
на .
фактично змінить цей регулярний вираз ("|').*?\1
і потім він буде відповідати"foo\"
в "foo \" bar"
. Однак, [^\1]
важко дістатися до роботи. @ Mathiashansen - Вам краще з непростим і дорогим (?!\1).
(таким чином, цілий регулярний вираз, з деяким очищенням ефективності, був би (["'])(?:\\.|(?!\1).)*+\1
. Це +
необов’язково, якщо ваш двигун не підтримує його.
Варіант, який раніше не торкався:
Це має додатковий бонус за можливість правильно співставити відкриті теги.
Скажімо, у вас був такий рядок; String \"this "should" NOT match\" and "this \"should\" match"
Тут \"this "should" NOT match\"
не повинно відповідати і "should"
повинно бути. На додаток до цього this \"should\" match
слід відповідати, а \"should\"
не слід.
Перший приклад.
// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';
// The RegExp.
const regExp = new RegExp(
// Match close
'([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
'((?:' +
// Match escaped close quote
'(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
// Match everything thats not the close quote
'(?:(?!\\1).)' +
'){0,})' +
// Match open
'(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
'g'
);
// Reverse the matched strings.
matches = myString
// Reverse the string.
.split('').reverse().join('')
// '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'
// Match the quoted
.match(regExp)
// ['"hctam "\dluohs"\ siht"', '"dluohs"']
// Reverse the matches
.map(x => x.split('').reverse().join(''))
// ['"this \"should\" match"', '"should"']
// Re order the matches
.reverse();
// ['"should"', '"this \"should\" match"']
Гаразд, зараз пояснимо RegExp. Це регулярне вироблення легко розбити на три частини. Так:
# Part 1
(['"]) # Match a closing quotation mark " or '
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
# Part 2
((?: # Match inside the quotes
(?: # Match option 1:
\1 # Match the closing quote
(?= # As long as it's followed by
(?:\\\\)* # A pair of escape characters
\\ #
(?![\\]) # As long as that's not followed by an escape
) # and a single escape
)| # OR
(?: # Match option 2:
(?!\1). # Any character that isn't the closing quote
)
)*) # Match the group 0 or more times
# Part 3
(\1) # Match an open quotation mark that is the same as the closing one
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
Це, мабуть, набагато чіткіше за формою зображення: згенеровано за допомогою регулятора Jex
Зображення на github (JavaScript Regular Expression Visualizer.) Вибачте, я не маю достатньо високої репутації, щоб включати зображення, тож це лише посилання на даний момент.
Ось суть прикладу функції, що використовує цю концепцію, яка є дещо досконалішою: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js
Треба пам’ятати, що регулярні виразки - це не срібна куля для всього рядка. Деякі речі простіше зробити курсором і лінійними, ручними, шукатими. CFL буде робити трюк досить тривіально, але не так багато реалізацій CFL (AFAIK).
Більш обширна версія https://stackoverflow.com/a/10786066/1794894
/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/
Ця версія також містить
“
та закрити ”
)Заплутався в регексапалі і закінчився цим регексом: (Не питайте мене, як це працює, я ледве розумію навіть те, що я написав це лол)
"(([^"\\]?(\\\\)?)|(\\")+)+"
Якщо його шукати з самого початку, можливо, це може спрацювати?
\"((\\\")|[^\\])*\"
Я зіткнувся з подібною проблемою, намагаючись видалити цитовані рядки, які можуть заважати розбору деяких файлів.
Я закінчився двоступеневим рішенням, яке перемагає будь-який складний регулярний вираз, який ви можете придумати:
line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful
Легше читати і, мабуть, більш ефективно.
Якщо ваш IDE - це IntelliJ Idea, ви можете забути всі ці головні болі і зберегти ваш регулярний вираз у змінній String, і при копіюванні та вставці його всередині подвійної лапки він автоматично зміниться у прийнятний для регулярного виведення формат.
приклад на Java:
String s = "\"en_usa\":[^\\,\\}]+";
тепер ви можете використовувати цю змінну у своєму регулярному виразі або де завгодно.