2010-02-09 4 views
3

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

Пример # 1
входной строки: 'hello'
первый маркер: '
второй маркер: hello
третий маркер: '

Пример # 2
входная строка: 'hello world'
первый маркер: '
второй маркер: hello world
третий маркер: '

Пример # 3
входная строка: hello world
первый маркер: hello
второй маркер: world

, т. Е. Разделите строку только в том случае, если она НЕ в одинарных кавычках, а одинарные кавычки должны быть в их собственном токене.

Это то, что я до сих пор:

string pattern = @"'|\s"; 
Regex RE = new Regex(pattern); 
string[] tokens = RE.Split("'hello world'"); 

Это будет работать, например, # 1 и пример # 3, но это не будет работать, например, 2 #. Мне интересно, есть ли теоретически способ добиться того, что я хочу с помощью регулярных выражений.

+0

Что вы ожидаете произойдет за строка: привет «миру»? (т. е. смешанные кавычки и слова без кавычек) – Paolo

+0

token1: hello token2: 'token3: toorld token4:' – foreyez

+0

Вы можете сначала разделить на цитированное строковое регулярное выражение, а затем разделить каждую полученную строку. – 2010-02-09 22:07:11

ответ

1

Хотя можно было бы сопоставить ' и текст внутри отдельно, а также в качестве альтернативы соответствовать тексту в одиночку, RegExp не допускает неопределенного количества совпадений. Или лучше сказать, вы можете сопоставлять только те объекты, которые вы явно указываете в выражении. Таким образом, ((\w+)+\b) теоретически может соответствовать всем словам один за другим. Внешняя группа будет правильно соответствовать всему тексту, а также внутренняя группа будет правильно соответствовать словам, но вы сможете ссылаться только на последнее совпадение.

Невозможно сопоставить группу совпадающих совпадений (странное предложение). Единственный возможный способ - совместить строку и , затем разделить ее на отдельные слова.

+0

да, вот что я думал ... но давайте посмотрим, если кто-нибудь все-таки придумает что-нибудь;) – foreyez

+0

никто не дал мне отличных ответов .. atleast u были честны – foreyez

+0

Не совсем. По вашей логике, регулярное выражение не может использоваться для сопоставления всех чисел из текста, например. Но они могут, довольно легко, на всех вкусах. ** Вам не нужны группы захвата для каждой строки. ** – Kobi

2

'[^']+' будет соответствовать тексту внутри одинарных кавычек. Если вы хотите его сгруппировать, (')([^']+)('). Если совпадений не найдено, просто используйте регулярный разделитель строк. Я не думаю, что имеет смысл попытаться сделать все это в одном регулярном выражении.

РЕДАКТИРОВАТЬ: Кажется, что ваши комментарии к вопросу о том, что вы на самом деле хотите, чтобы это применялось к более крупному блоку текста, а не только к простым входам, как вы указали. Если это так, то я не думаю, что регулярное выражение - это ваш ответ.

+0

Правильно, вы не можете создать регулярное выражение для разбора неопределенного количества токенов (по крайней мере, не на одном шаге). –

5

Вы можете создать простой лексер, который будет включать в себя каждый из токенов один за другим. Таким образом, у вас будет список регулярных выражений и будет пытаться сопоставить один из них в каждой точке. Это самый простой и самый чистый способ сделать это, если ваш ввод - это нечто очень простое.

+0

Да, но я хочу иметь «привет мир» как единственный токен. Я нахожу regex.split() очень хорошим в создании токенов, за исключением одного случая ... – foreyez

+0

@ Шнитель: Тогда вы должны определить случай в своем лексере, чтобы потреблять больше текста, если он находится внутри одинарных кавычек. Да, regex.split() - очень простой вариант, и из того, что вы хотите сделать, кажется, вам может понадобиться нечто более мощное. Кроме того, вы можете использовать один из генераторов лексера и синтаксического анализатора для C#, они могут сделать вашу жизнь намного проще. –

+0

+1 Я думаю, что ОП пытается водить винты молотком. –

3

Используйте токеновый парсор, чтобы разделить на токены. Используйте регулярное выражение, чтобы найти строковые шаблоны.

1

Вы можете сначала разделить на цитируемую строку, а затем продолжить tokenize.

foreach (String s in Regex.Split(input, @"('[^']+')")) { 
    // Check first if s is a quote. 
    // If so, split out the quotes. 
    // If not, do what you intend to do. 
} 

(Примечание: вам нужно скобки в шаблоне, чтобы убедиться, что регулярное выражение.Split возвращает те тоже)

+0

Не будет 'Split' удалять строки между кавычками? – Kobi

+0

Я так не думаю, но есть различия между версиями .Net. Я помню, что я использовал эту идею, чтобы быстро написать эффективный синтаксический анализатор lexer +. Возможно, это было не оптимально, но показалось достаточно хорошим даже для струн среднего размера. – 2010-02-10 14:09:06

+0

Проверьте, что ваш код удаляет токены между кавычками - 'Split' не включает разделитель в свои результаты. – Kobi

0

Попробуйте это регулярное выражение:

([']*)([a-z]+)([']*) 

Это находит 1 или более одиночные кавычки в начале и в конце строки. Затем он находит 1 или более символов в наборе a-z (если вы не зададите его нечувствительность к регистру, он найдет только символы нижнего регистра). Он группирует их так, что группа 1 имеет «, группа 2 (или более) имеет слова, которые разбиваются на что-либо, что не является символом a-z, а последняя группа имеет одинарную цитату, если она существует.

1

Не совсем то, что вы пытаетесь сделать, но регулярные условия выражения может помочь, как вы искать решение:

(?<quot>')?(?<words>(?(quot)[^']|\w)+)(?(quot)') 

Если цитата найдена, то она соответствует, пока не кавычка не найдено , В противном случае просматриваются слова. Ваши результаты представлены в группах с именем «quot» и «words».

+0

+1 - Я думаю, что это то, что ищет ОП. Это похоже на мой ответ, но более сложный (я думаю, что здесь работает лучше). Кроме того, у вас была репутация 999. – Kobi

1

Вы будете иметь трудное время, используя Split здесь, но вы можете использовать MatchCollection, чтобы найти все матчи в вашей строке:

string str = "hello world, 'HELLO WORLD': we'll be fine."; 
MatchCollection matches = Regex.Matches(str, @"(')([^']+)(')|(\w+)"); 

регулярное выражение для поиска строки между одинарными кавычками. Если он не может найти его, это займет одно слово.
Теперь он становится немного сложным - .net возвращает коллекцию Match s. В каждом матче есть несколько Group s - первая группа имеет целую цепочку ('hello world'), а остальные имеют подвыборы (', hello world, '). Кроме того, вы получаете много пустых неудачных групп.
Вы все равно можете легко перебирать и получать свои матчи. Вот пример использования LINQ:

var tokens = from match in matches.Cast<Match>() 
      from g in match.Groups.Cast<Group>().Skip(1) 
      where g.Success 
      select g.Value; 

tokens теперь коллекция строк:
hello, world, ', HELLO WORLD, ', we, ll, be, fine

+0

Незначительное примечание: вы можете заменить '\ w +' на '\ S +', чтобы сохранить другие символы. – Kobi

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