Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Wyrazenia Regularne, kolorowanie skladni za pomoca php
y3ti
post 19.08.2004, 12:49:26
Post #1





Grupa: Zarejestrowani
Postów: 40
Pomógł: 0
Dołączył: 19.08.2004
Skąd: Pruszków

Ostrzeżenie: (0%)
-----


Witam,

Wraz z moim znajomym piszemy skrypt odpowiedzialny za kolorowanie skladni w artykulach i forum w naszym serwisie. Jak dotad wszystko nam szlo jak po masle, ale natknelismy sie na pewien problem, z ktorym od pewnego juz czasu nie mozemy
dac sobie sami rady.

Problem polega na tym, ze jak kolorujemy slowa kluczowe (dla przykladu niech to bedzie int z C) to slowa te nam sie koloruja, ale niestety rowniez wtedy, jesli
slowo to jest lancuchem znakow. Mamy powiedzmy taki oto prosty kod napisany w C:

Kod
#include <stdio.h>

int main()
{
   printf("Hello int World \n");

   return 0;
}



i teraz powiedzmy, ze chcemy pokolorowac wszystkie int na niebiesko, wiec:

  1. <?php 
  2.  
  3.  $zrodlo = join('', file('zrodlo.c'));
  4.  $zrodlo = htmlspecialchars( $zrodlo );
  5.  
  6.  $zrodlo = preg_replace('/bintb/', '<span style=\"color: blue\">int</span>', $zrodlo );
  7.  
  8. ?>


I teraz pytanie. Jak powinno wygladac wyrazenie regularne, aby nie kolorowalo tekstu w cudzyslowach?

Probowalem tak:

  1. <?php
  2.  
  3.  $zrodlo = preg_replace('/([^\"]*?)bintb(.*[^\"])/', '1<span style=\"color:blue\">int</span>2', $zrodlo );
  4.  
  5. ?>


Niestety tez nie dziala. Juz nie mam pomyslu jak mozna sobie z tym poradzic.

Bede wdzieczny za wszelkie informacje.
Go to the top of the page
+Quote Post
DeyV
post 19.08.2004, 14:30:30
Post #2





Grupa: Zarząd
Postów: 2 277
Pomógł: 6
Dołączył: 27.12.2002
Skąd: Wołów/Wrocław




Wydaje mi się, zę w takim przypadku najlepiej by było zobaczyć jak robią to inni.
Niestety - problem nie jest łatwy, i nie ma jednego dobrego rozwiązania.
Te które widziałem napisane w php nie zapewniają jednak 100% skteczności (jak choćby kolorowanie SQL na tym forum - które jest tylko delikatnie zmodyfikowanym orginalnym mechanizmem z IPB)

Widziałe natomiast niedawno skrypt, który kolorował kod dokłądnie tak, jak by "mi się to podobało" Niestety - jest napisany w JS... Mimo to sądzę, że przestudiowanie jesgo konstrukcji może przynieść Wam spory pożytek
http://gosu.pl/dhtml/JavascriptDecoder.html

ps. Brawo, cagrET


--------------------
"Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
Go to the top of the page
+Quote Post
cagrET
post 20.08.2004, 01:32:50
Post #3





Grupa: Zarejestrowani
Postów: 90
Pomógł: 0
Dołączył: 3.04.2003
Skąd: Opole

Ostrzeżenie: (0%)
-----


W tym dekoderze kolorowanie skladni dziala niestety tylko na Mozilli. Na IE nie dziala poniewaz string zawierajacy znak nowej lini "\n" ktory został wygenerowany przez javascript nie działa w tagach PRE, nie mam pojęcia czemu.

Jak znajdę trochę czasu to spróbuję napisać w php kolorowanie składni dla C/SQL i może dołącze mały tutorial (niestety pewnie po angielsku). W sumie to nie jest trudne, jak się idzie na skróty tak jak ja to zrobiłem, niezbyt profejonalnie, ale spełnia swoje założenia, najważniejsze że działa ! Już słyszałem od paru osób że jedynym słusznym rozwiązaniem tego problemu jest napisanie parsera, ktory zajmie z minimum 200 KB, a napisanie go zajmie z kilka miechów, no thx winksmiley.jpg

W sumie to kolorowanie tej skladni C mozna by napisac w javascript, a później mały skrypt który pobiera na stronie wszystkie elementy PRE z klasa np "clanguage" i je koloruje.
Kod
<pre class="clanguage">
#include <stdio.h>

int main()
{
  printf("Hello int World \n");

  return 0;
}
</pre>


--------------------
code.gosu.pl
Go to the top of the page
+Quote Post
y3ti
post 20.08.2004, 12:01:22
Post #4





Grupa: Zarejestrowani
Postów: 40
Pomógł: 0
Dołączył: 19.08.2004
Skąd: Pruszków

Ostrzeżenie: (0%)
-----


Postanowilem jeszcze raz poszukac na googlach i znalazlem kilka rozwiazan. Idealnym (no prawie) zostal projekt Geshi - skrypt w php do kolorowania skladni.

http://qbnz.com/highlighter/

Mozliwosci:

- dosc dobrze koloruje, sa drobne bledy, ale mozna je sobie odpusic
- projekt jest wciaz rozwijany
- numerowanie linii kodu
- latwa rozbudowa parsera (dodanie "nowych jezykow")
- latwo mozna modyfikowac style w kolorowaniu (te proponowane przez tworcow maja
brzydkie kolorki, ale to tylko kwestia gustu)

Jedyna wada jaka znalazlem jest to, ze nie zwraca nam lancucha z pokolorowanym tekstem, tylko odrazu wyswietla. Naszczescie mozna sie z tym uporac za pomoca
manipulacji buforem.
Go to the top of the page
+Quote Post
DeyV
post 20.08.2004, 13:14:13
Post #5





Grupa: Zarząd
Postów: 2 277
Pomógł: 6
Dołączył: 27.12.2002
Skąd: Wołów/Wrocław




Bardzo ciekawy projekt. Jestem pod wrażeniem. Załuje tylko, że powstał dopiero teraz (first release: 2004-07-17 05:00) ponieważ poświęciłem kiedyś sporo czasu na znalezienie czegoś takiego w php (w innych językach oczywiście były odpowiednie moduły) i niestety - nic z tego nie wyszło.

A teraz juyż chyba jest nawet odpowiedni mod dla bb, wykorzystujący ten system kolorowania. nono...


--------------------
"Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
Go to the top of the page
+Quote Post
Parti
post 20.08.2004, 13:14:16
Post #6





Grupa: Zarejestrowani
Postów: 116
Pomógł: 0
Dołączył: 22.07.2004

Ostrzeżenie: (0%)
-----


Cytat(cagrET @ 2004-08-20 02:32:50)
Już słyszałem od paru osób że jedynym słusznym rozwiązaniem tego problemu jest napisanie parsera, ktory zajmie z minimum 200 KB, a napisanie go zajmie z kilka miechów, no thx winksmiley.jpg

To bardzo ciekawe. Do kolorowania składni wystarczy lekser, a nie parser. Napisanie go wcale nie zajmuje pare miesięcy. Widze, że ostatnio ten temat dość często poruszany jest na forum. Proponuje zatem na początek zainteresować się programem GNU Enscript

Może kiedyś zmusze się do napisania czegoś, bo ten problem również i mnie troche interesuje.

Teraz podam przykład prostego leksera. Nie daje żadnej gwarancji, że działa. Jest mocno uproszczony. To tylko przykład jak napisać lekser.

  1. <?php
  2.  
  3.     class cToken
  4.     {
  5.         var $type;
  6.         var $val;
  7.     }
  8.     // typy tokenow
  9.     define('OTHER', 0);
  10.     define('OPERATOR', 1);
  11.     define('VARIABLE', 2);
  12.     define('COMMENT', 3);
  13.     define('STRING_VAL', 4);
  14.     define('NUMBER', 5);
  15.     define('IDEN', 6);
  16.     define('KEYWORD', 7);
  17.  
  18.     // kawalek kodu php do pokolorawania
  19.     $str = &#092;"echo 12 . \"jakis tekst i \"tekst\"\"; # komentarznecho funkcja($zmienna);\";
  20.     $pos = 0;
  21.     $len = strlen($str);
  22.  
  23.     $slowa_kluczowe = array('echo', 'class'); // itd.
  24.  
  25.     function gettoken(&$token)
  26.     {
  27.         global $pos;
  28.         global $str;
  29.         global $len;
  30.         global $slowa_kluczowe;
  31.  
  32.         if ($pos == $len) // doszlismy do konca napisu, zwracamy zero
  33.             return 0;
  34.  
  35.         switch ($str{$pos})
  36.         {
  37.             case &#092;" \":  // wszelkie białe znaki zostawiamy jak są
  38.             case &#092;"t\": 
  39.             case &#092;"r\":
  40.             case &#092;"n\": 
  41.                 $token->type = OTHER;
  42.                 $token->val = $str{$pos++};
  43.                 return -1;
  44.  
  45.             case &#092;";\": // tutaj trzeba by wypisac wszystkie jedno-znakowe operatory i znaki przestankowe
  46.             case &#092;"(\": case \")\":
  47.             case &#092;"[\": case \"]\":
  48.             case &#092;".\": $token->type = OPERATOR; $token->val = $str{$pos++}; return -1;
  49.  
  50.             // niektore znaki moga byc czescia dluzszego oeratora
  51.             case &#092;"+\":
  52.                 $token->type = OPERATOR;
  53.                 if ($str{$pos+1} == &#092;"+\") // operator ++
  54.                 {
  55.                     $token->val = &#092;"++\";
  56.                     $pos += 2;
  57.                 }
  58.                 else if ($str{$pos+1} == &#092;"=\") // operator +=
  59.                 {
  60.                     $token->val = &#092;"+=\";
  61.                     $pos += 2;
  62.                 }
  63.                 else // jednak jest tylko plus
  64.                 {
  65.                     $token->val = &#092;"+\";
  66.                     $pos++;
  67.                 }
  68.  
  69.                 return -1;
  70.             // tutaj trzeba by rozwazyc przypadki z innymi tego typu oeratorami jak -, --, -=, *, *= itp
  71.  
  72.             case &#092;"$\": // zmienna
  73.                 $nazwa = &#092;"\";
  74.                 $pos++;
  75.                 while (ctype_alnum($str{$pos}) || $str{$pos} == &#092;"_\")
  76.                 {
  77.                     $nazwa .= $str{$pos};
  78.                     $pos++;
  79.                 }
  80.  
  81.                 $token->type = VARIABLE;
  82.                 $token->val = '$' . $nazwa;
  83.  
  84.                 return -1;
  85.             
  86.             case &#092;"#\": // komentarz
  87.             // ten typ komentarza jest bardzo prosty do rozpatrzenia
  88.             // najtrudniejszy jest /* */
  89.                 $koment = &#092;"\";
  90.  
  91.                 while ($str{$pos} != &#092;"n\")
  92.                     $koment .= $str{$pos++};
  93.  
  94.                 $token->type = COMMENT;
  95.                 $token->val = $koment;
  96.                 
  97.                 return -1;
  98.  
  99.             case &#092;"\"\": // stala napisowa, podobnie dla '
  100.                 $napis = &#092;"\"\";
  101.                 $pos++;
  102.  
  103.                 while ($str{$pos} != &#092;"\"\")
  104.                 {
  105.                     if ($str{$pos} == &#092;"\") // wszelkie wyescapowane znaki
  106.                     {
  107.                         $napis .= &#092;"\";
  108.                         $pos++;
  109.                         $napis .= $str{$pos};
  110.                     }
  111.                     else
  112.                         $napis .= $str{$pos};
  113.  
  114.                     $pos++;
  115.                 }
  116.  
  117.                 $pos++;
  118.                 $token->type = STRING_VAL;
  119.                 $token->val = $napis . &#092;"\"\";
  120.  
  121.                 return -1;
  122.  
  123.             default:
  124.                 if (ctype_digit($str{$pos})) // rozwaze tylko liczby calkowite
  125.                 {
  126.                     $num = &#092;"\";
  127.  
  128.                     while (ctype_digit($str{$pos}))
  129.                         $num .= $str{$pos++};
  130.  
  131.                     $token->type = NUMBER;
  132.                     $token->val = $num;
  133.  
  134.                     return -1;
  135.                 }
  136.                 else if (ctype_alpha($str{$pos}) || $str{$pos} == &#092;"_\") // identyfikator jakis
  137.                 { // byc moze slowo kluczowe lub nazwa funkcji
  138.                     $iden = &#092;"\";
  139.  
  140.                     while (ctype_alnum($str{$pos}) || $str{$pos} == &#092;"_\")
  141.                         $iden .= $str{$pos++};
  142.  
  143.                     $token->val = $iden;
  144.  
  145.                     if (array_search($iden, $slowa_kluczowe) === false) // nie jest slowem kluczowym
  146.                     { // malo wydajne przeszukiwanie, tutaj wlasciwie trzeba by wpakowac jakis maly auto
  147. at skonczony
  148.                         $token->type = IDEN;
  149.                         return -1;                        
  150.                     }
  151.                     else // slowo kluczowe
  152.                     {
  153.                         $token->type = KEYWORD;
  154.                         return -1;
  155.                     }
  156.                 }
  157.                 else // bledny, nierozpoznany znak (w naszym przypadku poprostu go zwracamy)
  158.                 {
  159.                     $token->type = OTHER;
  160.                     $token->val = $str{$pos++};
  161.                     return -1;
  162.                 }
  163.         }
  164.     }
  165.  
  166.     $token = new cToken;
  167.  
  168.     echo &#092;"<pre>\";
  169.  
  170.     while (($t = gettoken($token)) != 0)
  171.     {
  172.         switch ($token->type)
  173.         {
  174.             case OTHER: echo $token->val; break;
  175.             case OPERATOR: echo &#092;"<font color=red>\" . $token->val . \"</font>\"; break;
  176.             case VARIABLE: echo &#092;"<font color=blue>\" . $token->val . \"</font>\"; break;
  177.             case COMMENT: echo &#092;"<font color=green>\" . $token->val . \"</font>\"; break;
  178.             case STRING_VAL: echo &#092;"<font color=pink>\" . $token->val. \"</font>\"; break;
  179.             case NUMBER: echo &#092;"<font color=gray>\" . $token->val . \"</font>\"; break;
  180.             case IDEN: echo &#092;"<font color=yellow>\" . $token->val . \"</font>\"; break;
  181.             case KEYWORD: echo &#092;"<font color=magenta>\" . $token->val . \"</font>\"; break;
  182.             default:
  183.                 echo &#092;"hm.. jakis blad?\";
  184.         }
  185.     }
  186.     
  187.     echo &#092;"</pre>\";
  188.  
  189. ?>


Ten post edytował Parti 20.08.2004, 13:35:16
Go to the top of the page
+Quote Post
cagrET
post 20.08.2004, 14:55:14
Post #7





Grupa: Zarejestrowani
Postów: 90
Pomógł: 0
Dołączył: 3.04.2003
Skąd: Opole

Ostrzeżenie: (0%)
-----


Cytat
To bardzo ciekawe. Do kolorowania składni wystarczy lekser, a nie parser.
Możliwe, miałem też na myśli ten Dekoder, czyli formatowanie kodu. Niestety jestem zielony w tej dziedzinie. Btw. masz może jakieś materiały / linki do artykułów na ten temat ? (leksery, parsery).


--------------------
code.gosu.pl
Go to the top of the page
+Quote Post
Parti
post 20.08.2004, 15:08:09
Post #8





Grupa: Zarejestrowani
Postów: 116
Pomógł: 0
Dołączył: 22.07.2004

Ostrzeżenie: (0%)
-----


Cytat(cagrET @ 2004-08-20 15:55:14)
Btw. masz może jakieś materiały / linki do artykułów na ten temat ? (leksery, parsery).

Polecam książke: Aho, Sethi, Ullman "Kompilatory" (jakiś czas temu wydana po Polsku) tzw. Dragon Book.

Manuale do Flexa (automatyczny generator lekserów) oraz Bisona (automatyczny generator parserów).

Jeszcze mi sie przypomniało. Na pierwszym roku informatyki na przedmiocie programowanie można poznać podstawy pisania kompilatorów. Tutaj skrypt do tego przedmiotu.

Ten post edytował Parti 20.08.2004, 15:10:58
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 12.08.2025 - 23:58