Regex для анализа тегов из строки. Стиль Flickr - PullRequest
3 голосов
/ 20 января 2009

Интересно, может ли кто-нибудь предоставить мне регулярные выражения, необходимые для разбора строки вроде:

'foo bar "тег из нескольких слов"'

в массив тегов, таких как:

["foo", "bar", "tag для нескольких слов"]

Спасибо

Ответы [ 6 ]

7 голосов
/ 20 января 2009

в рубине

scan(/\"([\w ]+)\"|(\w+)/).flatten.compact

Е.Г.

"foo bar \"multiple words\" party_like_1999".scan(/\"([\w ]+)\"|(\w+)/).flatten.compact
=> ["foo", "bar", "multiple words", "party_like_1999"]
2 голосов
/ 20 января 2009

Вы можете реализовать сканер для этого. Например, в Python это будет выглядеть примерно так:

import re
scanner = re.Scanner([
    (r"[a-zA-Z_]\w*", lambda s,t:t),       # regular tag
    (r"\".*?\"",      lambda s,t:t[1:-1]), # multi-word-tag
    (r"\s+",          None),               # whitespace not in multi-word-tag
    ])
tags, _ = scanner.scan('foo bar "multiple word tag"')
print tags
# ['foo', 'bar', 'multiple word tag']

Это называется лексическим анализом.

0 голосов
/ 20 января 2009

Вот так (стиль Perl):

^(?:"([^"]*?)"|(\S+?)|\s*?)*$

Пояснение:

^                    // from begginning                 
 (?:                  // non-capturing group of three alternatives
    "([^"]*?)"   // capture "tag"                                               "
 |
    (\S+?)        // capture tag
 |
    \s*?            // ignore whitespace
 )*                  
$                    // until the end of the line
0 голосов
/ 20 января 2009

Общее регулярное выражение, которое будет работать с любой функцией match-> array:

(?<=")[^"]+|\w+


(Если допускается использование не только буквенно-цифровых символов и кавычек, использование \S+ вместо \w+ может иметь смысл.)


Пример Ruby:

myarray = mystring.scan(/(?<=\")[^\"]+|\w+/)

(непроверенные)

0 голосов
/ 20 января 2009

Прежде всего, я бы предложил сделать это с помощью метода / функции split(), а не с помощью регулярных выражений. В большинстве языков есть что-то вроде этого, которое вы можете вызвать, чтобы разбить строку на слова (разделенные пробелами), и вы обычно можете указать верхнюю границу для количества частей, на которые вы хотите, чтобы она разбилась. Так в общем,

split('foo bar "multiple word tag"', ' ', 3)

, где 3 обозначает не более 3 частей, будет работать для вашего примера. Вы можете использовать метод / функцию trim() или strip() (или написать одну), чтобы удалить любые начальные и конечные кавычки.

Если вы намереваетесь делать это с помощью регулярных выражений, возможно, потому, что каждая строка может иметь переменное количество тегов, в некоторой степени это зависит от того, что именно вы используете для анализа, так как разные движки регулярных выражений иногда имеют разные способы представления одних и тех же вещей. И я не думаю, что это можно сделать с помощью простого старого регулярного выражения; вам понадобится код, чтобы согласиться с ним. Например, вот (псевдо -?) Решение с псевдокодом, использующее Perl-совместимое регулярное выражение (или что-то подобное):

pos = 0;
while pos < length(string):
    # match(regular expression, string to search, starting position for the search)
    m = match(/\s*(".+?"|\S+)?\s*/, string, pos);
    tag = m.group(1).strip('"');
    # process the tag

Для чего бы это ни стоило, я, вероятно, сделал бы это с DFA (дискретным конечным автоматом), который проходит через строку символьно-символьно, добавляя каждый из них в буфер и сбрасывая буфер, когда он достигает конца тега. (либо из-за пробела, либо из-за закрывающей кавычки). Может быть, это только я, но я чувствую, что это довольно простая задача анализа, и ее было бы легче понять (на мой взгляд) с точки зрения состояний DFA.

0 голосов
/ 20 января 2009

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

"^(?<username>[\w\d]+)@.*$"

Имя будет присутствовать в группе имен "username"

В вашем случае вы не пытаетесь получить подмножество входной строки. Вы пытаетесь сопоставить элементы всей строки. В конце дня регулярное выражение просто скажет «да, это соответствует» или «нет, это не так». Для того, чтобы получить содержимое, вам нужно разобрать строку.

...