Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Wyrazenia Regularne, kolorowanie skladni za pomoca php
y3ti
post
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
 
Start new topic
Odpowiedzi
Parti
post
Post #2





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

Posty w temacie


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 Aktualny czas: 22.08.2025 - 00:49