2010-11-10 2 views
-1

скажем, у меня очень длинная строка. строка имеет регулярные выражения в случайных местах. Можно ли использовать регулярное выражение для поиска регулярных выражений?Мы используем регулярное выражение для выражения выражений регулярных выражений?

+6

В чем разница между частью без регулярного выражения строки и частью регулярного выражения? – jball

+0

Конечно, но если вы собираетесь охватить весь синтаксис регулярных выражений, вы просто создали себе предварительный парсер. Я бы предложил предоставить больше спецификации для вопросов. –

+0

@ jball, ничего, они случайные персонажи –

ответ

4

(Предполагая, что вы ищете регулярное выражение JavaScript буквального, ограниченное /.)

Было бы достаточно просто просто посмотреть на все между /, но это не всегда может быть регулярным выражением. Например, такой поиск возвращает /2 + 3/ строки var myNumber = 1/2 + 3/4.Это означает, что вам нужно будет знать, что происходит перед регулярным выражением. Регулярному выражению должно предшествовать нечто иное, чем переменная или число. Это случаи, что я могу думать:

/regex/; 
var myVar = /regex/; 
myFunction(/regex/,/regex/); 
return /regex/; 
typeof /regex/; 
case /regex/; 
throw /regex/; 
void /regex/; 
"global" in /regex/; 

В некоторых языках вы можете использовать с просмотром назад, который может выглядеть следующим образом (непроверенные!):

(?=<^|\n|[^\s\w\/]|\breturn|\btypeof|\bcase|\bthrow|\bvoid|\bin)\s*\/(?:\\\/|[^\/\*\n])(?:\\\/|[^\/\n])*\/ 

Однако, JavaScript не поддерживает это. Я бы рекомендовал имитировать lookbehind, поставив часть регулярного выражения, предназначенную для соответствия самому литералу в группе захвата и доступа к ней. Все случаи, которые я отдаю себе отчет может соответствовать этому регулярному выражению:

(?:^|\n|[^\s\w\/]|\breturn|\btypeof|\bcase|\bthrow|\bvoid|\bin)\s*(\/(?:\\\/|[^\/\*\n])(?:\\\/|[^\/\n])*\/) 

ПРИМЕЧАНИЕ: Это регулярное выражение иногда приводит к ложным срабатываниям в комментариях.

Если вы хотите, чтобы также захватить модификаторы (например /regex/gim), используйте

(?:^|\n|[^\s\w\/]|\breturn|\btypeof|\bcase|\bthrow|\bvoid|\bin)\s*(\/(?:\\\/|[^\/\*\n])(?:\\\/|[^\/\n])*\/\w*) 

Если есть зарезервированные слова, я пропускаю, что может сопровождаться регулярным выражением буквального, просто добавьте в конце первая группа: |\bключевого слова

Все, что остается тогда, чтобы получить доступ к группе захвата, используя код похож на следующее:

var codeString = "function(){typeof /regex/;}"; 
var searchValue = /(?:^|\n|[^\s\w\/]|\breturn|\btypeof|\bcase|\bthrow)\s*(\/(?:\\\/|[^\/\*\n])(?:\\\/|[^\/\n])*\/)/g; 
    // the global modifier is necessary! 
var match = searchValue.exec(codeString); // "['typeof /regex/','/regex/']" 
match = match[1]; // "/regex/" 

UPDATE
Я просто исправили ошибку с регулярным выражением в отношении сбежавших слэш, что повлекло бы за это получить только /\/ из регулярного выражения, как /\/hello/

UPDATE 4/6
Добавлена ​​поддержка для void и in. Вы не можете слишком винить меня за то, что не включаете это сначала, так как даже Stack Overflow не делает этого, если вы посмотрите на синтаксическую раскраску в первом блоке кода.

1

Это не лучший способ для этого.

Вы можете сделать это с некоторой степенью уверенности (используя EOL, чтобы разбить на подстроки и найти те, которые выглядят как регулярные выражения, возможно ограниченные кавычками), однако не забывайте, что очень длинная строка CAN может быть регулярным выражением , поэтому у вас никогда не будет полной уверенности в использовании этого подхода.

3

Что вы подразумеваете под "регулярным выражением"? aaaa - действительное регулярное выражение. This is also a regular expression. Если вы имеете в виду литерал регулярных выражений, вам может понадобиться примерно следующее: /\/(?:[^\\\/]|\\.)*\// (адаптировано от here).

UPDATE

slebetman делает хорошую точку; Литералам регулярных выражений не нужно начинать с /. В Perl или sed они могут начинаться с того, что вы хотите. По существу, то, что вы пытаетесь сделать, является рискованным и, вероятно, не будет работать для всех случаев.

+3

Реляционный литерал зависит только от языка программирования. В tcl литерал регулярного выражения делится на {}. В C это «". И в Perl его можно разделить на все, что вы выберете. – slebetman

+0

@siebetman Хорошая точка. Я подумал об этом, но забыл упомянуть об этом. Будет обновляться. –

1

Да, если вы знаете, будет ли (и как!) Ваше регулярное выражение ограничено. Скажем, например, что ваша строка является чем-то вроде

aaaaa...aaa/b/aaaaa 

где «Ь» является «регулярное выражение» разграничены по характеру / (это почти базовый сценарий); вам нужно сканировать строку для ожидаемого разделителя, извлечь все, что находится внутри разделителей (обращая внимание на escape-символы), и вы должны быть установлены.

Это если ваш разделителем является известный персонаж и если вы уверены, что он появляется четное число раз, или вы хотите отказаться от остальных (например, какой набор разделителей вы рассматриваете в следующая строка: aaa/b/aaa/c/aaa/d)

Если это так, то вам нужно следовать тем же соображениям, что и вы, чтобы найти подстроку в заданной строке. Когда вы найдете первое регулярное выражение, продолжайте разбор, пока не нажмете конец строки или не найдете другое регулярное выражение и так далее.

Я подозреваю, что вы ищете «общее правило» для поиска любой строки, которая после разбора приведет к действительному регулярному выражению (скажем, мы говорим о POSIX regexp - попробуйте man re_format, если вы под BSD). Если это так, вы можете попробовать каждую возможную подстроку каждой длины данной строки и передать ее парсеру regexp для корректности синтаксиса. Тем не менее, вы ничего не доказали с точки зрения правильности регулярного выражения, то есть на то, что действительно совпадают.

Если это то, что вы пытаетесь сделать, я настоятельно рекомендую найти другой способ или объяснить, что вы пытаетесь сделать здесь.