2012-04-18 6 views
4

Я читаю информацию из форматированной строки. формат выглядит следующим образом:regex для синтаксического анализа строки с экранированными символами

"foo:bar:beer:123::lol" 

Все между «:» есть данные, которые я хочу, чтобы извлечь с регулярным выражением. Если a: за ним следует другое: (например, «::») данные для этого должны быть «» (пустая строка).

В настоящее время я разборе его с этим регулярным выражением:

(.*?)(:|$) 

Теперь пришла мне в голову, что «:» может существовать в данных, а также. Поэтому его нужно избегать. Пример:

"foo:bar:beer:\::1337" 

Как я могу изменить свое регулярное выражение, так что он соответствует «\:» как данные, тоже?

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

Спасибо, Макфарлейн

ответ

3
var myregexp = /((?:\\.|[^\\:])*)(?::|$)/g; 
var match = myregexp.exec(subject); 
while (match != null) { 
    for (var i = 0; i < match.length; i++) { 
     // Add match[1] to the list of matches 
    } 
    match = myregexp.exec(subject); 
} 

Вход: "foo:bar:beer:\\:::1337"

Выход: ["foo", "bar", "beer", "\\:", "", "1337", ""]

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

Объяснение:

(   # Match and capture: 
(?:  # Either match... 
    \\.  # an escaped character 
|   # or 
    [^\\:] # any character except backslash or colon 
)*  # zero or more times 
)   # End of capturing group 
(?::|$) # Match (but don't capture) a colon or end-of-string 
+0

Я получаю этот вывод: ["foo", "", "bar", "", "beer", "", "\" "," "," "," 1337 "," "] – McFarlane

+0

Ah , правильно. RegexBuddy достаточно «умный», чтобы опустить посторонние пустые совпадения, JavaScript и Python (где я сейчас тестирую это). Посмотрим, смогу ли я найти решение. –

+0

ваш обновленный пример соответствует данным, как ожидалось, но он продолжает возвращать ["", ""]. В вашем примере цикл приведет к бесконечному циклу, потому что совпадение никогда не будет равным нулю. Я ограничил цикл while, чтобы выполнить [subject.match (myregexp) .length-1] итерации. Я буду отмечать ваш ответ как правильный, хотя, потому что регулярное выражение является удивительным. Большое спасибо за ваши усилия. – McFarlane

2

Используйте отрицательное утверждение с просмотром назад.

(.*?)((?<!\\):|$) 

Это будет соответствовать только :, если это не предшествует \.

+0

он работает в моем тесте регулярного выражения, но он не работает в моем коде. Я использую JavaScript как язык программирования. Кажется, у меня есть некоторые ограничения, хотя я не могу найти какую-либо страницу, определяющую их. – McFarlane

+3

JavaScript не поддерживает утверждения lookbehind. –

+0

Итак, используйте класс символов на месте, например '([^ \\]: | $)' –

1

Вот решение:

function tokenize(str) { 
    var reg = /((\\.|[^\\:])*)/g; 
    var array = []; 
    while(reg.lastIndex < str.length) { 
    match = reg.exec(str); 
    array.push(match[0].replace(/\\(\\|:)/g, "$1")); 
    reg.lastIndex++; 
    } 
    return array; 
} 

Он разбивает строку на лексемы в зависимости от характера :.

  • Но вы можете избежать : персонажа с \, если вы хотите быть частью маркеров.
  • вы можете избежать \ с \, если вы хотите быть частью маркера
  • любой другой \ не будет интерпретирован. (то есть: \a остается \a)
  • Таким образом, вы можете помещать любые данные в свои лексемы при условии, что данные правильно отформатированы перед началом работы.

Ниже приведен пример со строкой \a:b:\n::\\:\::x, который должен дать этот маркер: \a, b, \n, <empty string>, \, :, x.

>>> tokenize("\\a:b:\\n::\\\\:\\::x"); 
["\a", "b", "\n", "", "\", ":", "x"] 

В попытке быть более ясным: строки, помещенных в Tokenizer будет интерпретироваться, она имеет 2 особого характер: \ и :

  • \ будет иметь только особый смысл, только если следует \ или :, и эффективно «убежит» от этих символов: это означает, что они потеряют свое особое значение для токенизатора, и они будут считаться любым нормальным персонажем (и, следовательно, будут частью жетонов).
  • : - маркер, разделяющий 2 жетона.

Я понимаю, что ОП не просил слэш сбежать, но другим зрителям может понадобиться полная библиотека разбора, позволяющая любому символу в данных.

Смежные вопросы