Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[boost::regex] Bałagan z backslash'ami

Ostatnio zmodyfikowano 2013-12-24 13:40
Autor Wiadomość
kubawal
Temat założony przez niniejszego użytkownika
[boost::regex] Bałagan z backslash'ami
» 2013-12-23 16:49:57
Witam!

Piszę sobie parser na potrzeby mojej własnej gry i regex'y jak zwykle odmawiają pomocy :/
Dane wejściowe do parsera są w formacie:

TYP nazwa: dane
I to mi działa.
Dodałem także obsługę tablic w formacie:

TABLE(TYP) nazwa:
{
0: dane0
1: dane1
2: dane2
}
I to mi nie działa.

Korzystam z kodu:
C/C++
string node; // węzeł do sparsowania
//...
regex reg( "(\\w+) ([\\w\\d]+): (.+)" ); // wzorzec na zwykły węzeł
regex regTbl( "^TABLE\\((\\w+)\\) ([\\w\\d]+):$" // wzorzec na węzeł tablicowy
"^(\\{$"
"^((\\d+): (.+)$)+"
"^\\})$" );

if( !regex_match( node, m, reg ) )
{
    // nie udało się dopasować do zwykłego węzła
    if( !regex_match( node, m, regTbl ) ) // więc próbujemy dopasować węzeł jako tablicę
    // ani węzeł, ani tablica, czyli coś jest źle...
         error( "Parser: Nie można dopasować węzła z wartości:\n" + node );
    else
    // dopasowywanie tablicy
    {
        //...
    }

I przy danych np.

TABLE(INT) t1:
{
0: 8
1: 9
2: 10
}

Wyświetla mi się:

Parser: Nie można dopasować węzła z wartości:
TABLE(INT) t1:
{
0: 8
1: 9
2: 10
}

Kiedy wyświetlam wzorzec na węzeł tablicowy, to wyświetla się mniej więcej takie coś:
^TABLE\((\w+)\) ([\w\d]+):$^(\{$^((\d+): (.+)$)+^\})$

Podejrzewam, że to jakiś problem z zastosowaniem backslashów.

PS: Używam boost::regex
P-99961
kubawal
Temat założony przez niniejszego użytkownika
» 2013-12-23 16:55:41
@offtop: Czy mi się zdaje, czy ten artykuł jest trochę podobny do mojego, z tej strony([C++] Wyrażenia regularne (C++11 / boost))?
P-99963
Monika90
» 2013-12-24 08:06:14
Na backslashe mogą pomóc Raw String Literals, ale to nie backslashe są tu problemem. Chodzi o to, że $ dopasowuje się w stringu przed znakiem \n, a ^ po, co znaczy, że pomiędzy końcem linii, a początkiem następnej jest jeszcze new-line. Więc zamiast ^$ powinieneś użyć ^\n$, albo po prostu \n, a najlepiej dopuścić w tych miejscach dowolny (także pusty) ciąg białych znaków, czyli \\s*.

Drugi problem jest taki, że jak masz grupę, która może się powtarzać np.: (jakiś-wzorzec)+, to po dopasowaniu będziesz miał dostęp tylko do ostatniego podciągu, który pasował do wzorca w nawiasach. Np. dla takiego tekstu:
TABLE(INT) t1:
{
0: 8
1: 9
2: 10
}
i wzorca TABLE\\((\\w+)\\) ([\\w\\d]+):\n(\\{\n((\\d+): (.+)\n)+^\\})
m[4] będzie zawierało "2: 10\n", m[5] "2", a m[6] "10", ale "0: 8\n" i "1: 9\n" nigdzie się nie zapiszą.

Z tym że biblioteka boost pozwala to zmienić za cenę spadku wydajności - trzeba ją rekompilować z opcją BOOST_REGEX_MATCH_EXTRA, co jest opisane tu http://www.boost.org/doc/libs​/1_55_0/libs/regex/doc/html​/boost_regex​/captures.html#boost_regex.captures.repeated_captures.

Porada dnia:
Nie warto kombinować z wyrażeniami regularnymi, prościej jest napisać parser w C++.
P-100021
kubawal
Temat założony przez niniejszego użytkownika
» 2013-12-24 13:19:26
to po dopasowaniu będziesz miał dostęp tylko do ostatniego podciągu
Ja sobie tylko sprawdzam, czy on pasuje do tablicy, a później wyciągam wartości z poszczególnych wierszy za pomocą regex'a (\\d+): (.+)\n)

Porada dnia:
Nie warto kombinować z wyrażeniami regularnymi, prościej jest napisać parser w C++.

No właśnie w tym problem, że piszę uniwersalny parser i regex'y są chyba najlepszym rozwiązaniem. Poza tym regex'y boost'a będą na pewno szybsze, niż jakiekolwiek moje rozwiązanie.
P-100038
Elaine
» 2013-12-24 13:40:50
No właśnie w tym problem, że piszę uniwersalny parser i regex'y są chyba najlepszym rozwiązaniem.
Regeksy prawie nigdy nie są najlepszym rozwiązaniem. Nadają się tylko do gramatyk regularnych, dla bardziej skomplikowanych są po prostu zbyt mało ekspresywne.
Poza tym są strasznie nieczytelne do wszystkiego poza najprostszymi rzeczami – chyba, że piszesz w Lispie i możesz sobie zrobić makro (a tak naprawdę użyć istniejącego), które przerobi bardziej czytelną formę przypominającą trochę parser combinator na ciąg znaków z tymi wszystkimi krzaczkami. Ale ty nie piszesz w Lispie.
Poza tym regex'y boost'a będą na pewno szybsze, niż jakiekolwiek moje rozwiązanie.
Regeksy są wolne w porównaniu do rozsądnie napisanego ręcznego parsera. Rozsądnie napisać parser jest łatwo.
P-100056
« 1 »
  Strona 1 z 1