Dziś jest piątek, 22 sierpnia 2008 roku (z kalendarza...)

Escaping zabija

Character escaping, czyli wyłączanie z przetwarzania tekstu znaków go kończących, może dobić każdego twórcę parserów/kompilatorów pracującego w nieprzystosowanym do tego celu języku. Jeżeli w dodatku jest to język interpretowany, programista ma ochotę zamordować osobę odpowiedzialną za NIEWŁĄCZENIE do niego żadnego narzędzia, które by to choć trochę ułatwiło i przyspieszyło.

Właśnie jestem po trzygodzinnym blitzkriegu Open Power Forms + Open Power Template. Sporo czasu zmarnowałem na pozornie prosty problem: jak podzielić taki ciąg: tekst tekst tekst; tekst tekst tekst; tekst "alala ; bebe" mo; lololo według średników, ale tylko tych nieznajdujących się w cudzysłowach. Dotychczas OPT robił to ręcznie, ale obsługiwał jedynie cudzysłowy, natomiast apostrof już nie (ewidentne niedopatrzenie). W każdym razie pierwsze próby polegały na układaniu wyrażeń regularnych, które by się tym zajęły. Prawdopodobnie jednak ich napisanie jest niemożliwe z technicznego punktu widzenia, a przynajmniej mi się za Chiny nie udało tego wykonać.

Później przyszedł mi bardzo dobry pomysł, aby wykorzystać technikę dzielenia na tokeny. Otrzymany w wyrażeniu wynik wprawdzie wymaga dodatkowego przetworzenia, ale jest to już tylko mała formalność w porównaniu z tym, co było. Oto, co wykombinowałem:

<?php
	$rDoubleQuoteString = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
	$rReversedQuoteString = '`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`';
	$rSingleQuoteString = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
	$text = 'mamamama; dkdkdkd; jmdjkd "fkfk;fgfdg"; kfkf `dklj;` kjdlkj; djhfk \'dkjd;\' dsf';
	echo '<pre>';
	preg_match_all('/(?:'.
		$rDoubleQuoteString.'|'.
		$rSingleQuoteString.'|'.
		$rReversedQuoteString.'|;|[^"\'`;]*)/x', $text, $found);
	$params = array(0 => '');
	$i = 0;
	foreach($found[0] as $item)
	{
		if($item == ';')
		{
			$i++;
			$params[$i] = '';
		}
		else
		{
			$params[$i] .= $item;
		} 
	}
	print_r($params);
	echo '</pre>';
?>

Mamy tu pięć grup tokenów: teksty w cudzysłowach, apostrofach i odwróconych apostrofach, średniki oraz pozostały tekst. W wyniku znajdują się pasujące do nich elementy. W pętli wystarczy tylko łączyć je w jeden ciąg, a w przypadku napotkania średnika zacząć tworzyć nowy. Ot, cała filozofia, a tyle zachodu.

Na pocieszenie (rany, czyje? Na pewno nie moje!) dodam, że jeszcze trzeba podobną sztuczkę zrobić z dzieleniem całego szablonu na znaczniki i tekst statyczny. Włączcie sobie tryb kompatybilności z XML'em, parsując taki szablon:

<opt:if test="$obiekt->pole">test</opt:if>

Podpowiem, że OPT za znacznik weźmie tę część: <opt:if test="$obiekt-> i wyświetli błąd o... nieprawidłowej liczbie parametrów. Najprawdopodobniej podobnie się stanie z nawiasami klamrowymi. W dokumentacji PHP trafiłem na takie wyrażenie:

/(<(?:[^<>]+(?:"[^"]*"|\\'[^']*\\')?)+>)/

do zastosowania z preg_split. Według autora działa. Nie omieszkam tego sprawdzić, a jeżeli wypali, poeksperymentuję w tym kierunku.

Powrót

Komentarze

Napisał hwao w poniedziałek, 9 stycznia 2006 o 21:19

tez sie zastanawialem czemu nie ma jakiegos parse_config(?) ;)

Napisał Zyx w poniedziałek, 9 stycznia 2006 o 21:40

Ha, teraz mam zastrzał z tym drugim problemem. Na razie spróbuję zrobić to na identycznej technice: regex+odpowiedni algorytm scalający, ale ładnie się omorduję w takim razie z delimiterami. Na 100% trzeba będzie zmienić ich format, a samo spajanie też jakoś zoptymalizuję na wzór yylex() w analizatorach leksykalnych made by YACC: będzie sobie pętla, w każdym przebiegu wywoływana będzie odpowiednia metoda, która pobierze kolejny element, a jak takowego nie będzie, dajemy NULL i koniec. Odpadnie jedno buforowanie tego wszystkiego, co będzie miało ogromne znaczenie przy dużych szablonach. Budowa drzewka węzłów już jest wystarczająco czasochłonna :).

Napisał .johnny w wtorek, 10 stycznia 2006 o 16:28

<opt:if test="$obiekt->pole">test</opt:if>
Ale to, o ile się nie mylę, nie jest well-formed XML. Wypadałoby zastąpić "$obiekt->pole" przez "$obiekt-&gt;pole". Jeżeli dla kogoś to za dużo pisania, to nie wiem po co pisze szablony jako XML... lekka hipokryzja ;-)

Napisał Zyx w wtorek, 10 stycznia 2006 o 16:35

XML w OPT jest przetwarzany przez ten sam parser, który parsuje "normalne" szablony, tyle że w trybie emulacji. Dlatego akceptowanych jest sporo nieprawidłowych struktur. Niemniej dobrze, że zwróciłeś uwagę na to &amp;gt; - jak nie będzie w wersji 1.0.0 tego, to już 1.0.1 będzie takie cuda akceptować na pewno. Problem mimo to nie znika. Przecież trzeba to zrobić choćby dla nawiasów klamrowych.

Napisał hwao w wtorek, 10 stycznia 2006 o 17:42

imho to juz parodia zeby bylo gt; ;)
Zastap -> kropka i tyle... jak w kazdym normalnym jezyku ;)

Napisał eXtreme w środę, 11 stycznia 2006 o 10:25

Ale kropka jest do tablic. :)

Strona 1 z 1 :: 1

Skomentuj

NickInformacja
E-mailTylko do użytku wewnętrznego.
WWWNie zapomnij o http://
LayoutNapisz tu, czy widzisz dzienny czy nocny layout.
WpisFormatowanie wiki
Internauto, pamiętaj! Wolność to nie samowola - dbaj o kulturę wypowiedzi oraz dyskusji w sieci.

Na Zyxist.com panuje swoboda wyrażania opinii oraz krytyki pod dowolnym adresem. Jedyny warunek: musi być ona kulturalna i rzeczowa. Na chamstwo, prostactwo lub jawne obrażanie kogokolwiek nie ma tu miejsca i takie komentarze są bardzo szybko usuwane. Jeśli zamierzasz polemizować z treścią wpisu, wpierw uważnie ją przeczytaj.

© Tomasz "Zyx" Jędrzejewski 2005 - 2008 | Wykonanych zapytań: 2 | Serwer wirtualny zapewnia