Jak uprościć funkcje, którta służy do kolorowania składni

0

Napisałem sobie funkcję, która służy do kolorowania składni kodu źródłowego jednak w tej funkcji jest dużo porównań i to trochę źle wygląda nie wiem czy tak to może zostać, ale jak nie to jakie byście proponowali inne rozwiązanie.

   function kolorowanie($plik3) {
  $cudzy = false;
  $zmienna = false;
  $instrukcje = false;
  $licznik = 0;
  while ( $licznik <= count($plik3)  ) {
  //jeżeli znak będzie się zaczynał od znaku dolara to znaczy, że to jest zmienna i pokolorować
  if ($plik3[$licznik] == "\$") $zmienna = true;
  //jeżeli będzie zakończenie wpisywania zmiennej
  else if ( ($plik3[$licznik] == " " or $plik3[$licznik] == "=" or $plik3[$licznik] == "-" or $plik3[$licznik] == ")"  or $plik3[$licznik] == "\"" or $plik3[$licznik] == ";") and $zmienna == true ) $zmienna = false;
  
  //to samo dla cudzysłowia
  if ($plik3[$licznik] == "\"" and $cudzy == true) $cudzy = false;
  //zakończenie cudzysłowia
  else if ($plik3[$licznik] == "\"") $cudzy = true;
  //ifa
  if ($plik3[$licznik] == "i" and $plik3[$licznik+1] == "f" and $cudzy == false and ($plik3[$licznik-1] == " " or $plik3[$licznik-1] == "\n" ) and ($plik3[$licznik+2] == "{" or $plik3[$licznik+2] == "(" or $plik3[$licznik+2] == " ") ) $instrukcje = true;
  
  //zakończenie ifa
  if ($plik3[$licznik-2] == "i" and $plik3[$licznik-1] == "f" and $cudzy == false and ($plik3[$licznik-3] == " " or $plik3[$licznik-3] == "\n" ) and ($plik3[$licznik] == "{" or $plik3[$licznik] == "(" or $plik3[$licznik] == " ") ) $instrukcje = false;
  //itp.
  if ($plik3[$licznik] == "e" and $plik3[$licznik+1] == "l" and  $plik3[$licznik+2] == "s"  and  $plik3[$licznik+3] == "e" and $cudzy == false and ($plik3[$licznik-1] == " " or $plik3[$licznik-1] == "\n" ) and ($plik3[$licznik+4] == "{" or $plik3[$licznik+4] == "(" or $plik3[$licznik+4] == " ") ) $instrukcje = true;
  //itp.
  if ($plik3[$licznik-4] == "e" and $plik3[$licznik-3] == "l" and $plik3[$licznik-2] == "s" and $plik3[$licznik-1] == "e" and $cudzy == false and ($plik3[$licznik-5] == " " or $plik3[$licznik-5] == "\n" ) and ($plik3[$licznik] == "{" or $plik3[$licznik] == "(" or $plik3[$licznik] == " ") ) $instrukcje = false;
  
  //itp.
  if ($plik3[$licznik] == "f" and $plik3[$licznik+1] == "o" and $plik3[$licznik+2] == "r" and $cudzy == false and ($plik3[$licznik-1] == " " or $plik3[$licznik-1] == "\n" ) and ($plik3[$licznik+3] == "{" or $plik3[$licznik+3] == "(" or $plik3[$licznik+3] == " ") ) $instrukcje = true;
  //itp.
  if ($plik3[$licznik-3] == "f" and $plik3[$licznik-2] == "o" and $plik3[$licznik-1] == "r" and $cudzy == false and ($plik3[$licznik-4] == " " or $plik3[$licznik-4] == "\n" ) and ($plik3[$licznik] == "{" or $plik3[$licznik] == "(" or $plik3[$licznik] == " ") ) $instrukcje = false;
  //itp.
  if ($plik3[$licznik] == "w" and $plik3[$licznik+1] == "h" and $plik3[$licznik+2] == "i" and $plik3[$licznik+3] == "l" and $plik3[$licznik+4] == "e" and $cudzy == false and ($plik3[$licznik-1] == " " or $plik3[$licznik-1] == "\n" ) and ($plik3[$licznik+5] == "{" or $plik3[$licznik+5] == "(" or $plik3[$licznik+5] == " ") ) $instrukcje = true;
  //itp.
  if ($plik3[$licznik-5] == "w" and $plik3[$licznik-4] == "h" and $plik3[$licznik-3] == "i" and $plik3[$licznik-2] == "l" and $plik3[$licznik-1] == "e" and $cudzy == false and ($plik3[$licznik-6] == " " or $plik3[$licznik-6] == "\n" ) and ($plik3[$licznik] == "{" or $plik3[$licznik] == "(" or $plik3[$licznik] == " ") ) $instrukcje = false;

  if ($instrukcje == true) {
    print "<font color=grenn>" . $plik3[$licznik] . "</font>";
  }
  
  else if ($zmienna == true) {
    print "<font color=blue>" . $plik3[$licznik] . "</font>";
  }
  else if ($cudzy == true) {
    print "<font color=red>" . $plik3[$licznik] . "</font>";
  }
  else {
    print "<font color=black>" . $plik3[$licznik] . "</font>";
  }
  
  if ($plik3[$licznik] == "\n") print "<br>";

  $licznik++;
  }
  
  }
0

Zrób sobie tablicę, dla każdego typu operacji. Potem wykonujesz operacje na gotowym tekście, korzystając z funkcji str_replace, na zasadzie:

$content = str_replace("if", '<font color="green">if</font>', $content);

Ostatecznie dostaniesz np.:

 
foreach($greenElements as $g) {
  $content = str_replace($g, '<font color="green">' . $g . '</font>', $content);
}
0

Jak ustawiasz zmienne po warunku to zrób to w 2 linii np.

if ($plik3[$licznik] == "\"" and $cudzy == true) 
$cudzy = false;

Rozpisz sobie warunki na zmienne, wtedy lepiej będzie się to czytało.

if ($plik3[$licznik] == "\"" and $cudzy == true) $cudzy = false;

np. na

$isQuoteEnd = $plik3[$licznik] == "\"" and $cudzy == true
if($isQuoteEnd) 
$cudzy = false;

Ogólnie taki skrypt mógłbyś spokojnie kilkoma preg_replace_callback zrobić.

$string = 'if("trelefere\)
")
IF($STRING)
if()
taki tam kod';
  $returnedString = preg_replace_callback('/(if\s*(?:.*?(?:\"|\'|[^\\\])\s*\)))*/is',function($match){
	return "<font color=grenn>" . $match[0] . "</font>";
  },$string);
  echo $returnedString;
0
  1. Koledzy wcześniej mówili abyś nie używał wyrażeń regularnych. Absolutnie się z nimi nie zgadzam. Regexy przydają się w tego typu zabawach - chociaż naiwne podejście zareprezentowane przez @Xingu i @jackraymund na pewno się nie sprawdzi. Ale możesz zrobić coś takiego
function getWord($str, $pos) {
  if ($pos < 0) {
    return null;
  }
  preg_match('/(^|\W)(\w+)(\W|$)|/', $str, $match, 0, $pos ? $pos - 1 : 0);
  return isset($match[2]) ? $match[2] : null;
}

function getVar($str, $pos) {
  if ($pos < 0) {
    return null;
  }
  preg_match('/(^|\W)\$(\w+)(\W|$)|/', $str, $match, 0, $pos ? $pos - 1 : 0);
  return isset($match[2]) ? $match[2] : null;
}

// potem:
if ( $cudzy == false && getWord($plik, $licznik) == 'if') $instrukcje = true;
if ( $cudzy == false && getWord($plik, $licznik -2) == 'if') $instrukcje = false;
if ( $cudzy == false && getVar($plik, $licznik -2)) $zmienna = true;

Analogicznie załatwiasz stringi itd.

  1. Możesz pobawić się gramatykami. Kiedyś pisałem narzędzie do takich zabaw ( https://github.com/farafiri/PHP-parsing-tool ) które może ci się przydać
$parser = new \ParserGenerator\Parser('start           :=> rest++(stringContainer | keyword | anyword | variable).
                                               variable        :=> "$" anyword.
                                               stringContainer :=> string.
                                               anyword         :=> /[a-zA-Z0-9_]+/.
                                               keyword         :=> ( "echo" | "if" | "while" | "public" | "function").
                                               rest            :=> /[^"\'$a-zA-Z0-9_]*/.', array('ignoreWhitespaces' => false, 'defaultBranchType' => 'PEG'));

$parsed = $parser->parse(""if (\$x < \$y) echo 'if \$x echo'"");
$parsed->inPlaceTranslate("variable", function($node) {return '<span style="color:#b55;">' . $node . '</span>';});
$parsed->inPlaceTranslate("keyword", function($node) {return '<span style="font-weight: bold;">' . $node . '</span>';});
$parsed->inPlaceTranslate("stringContainer", function($node) {return '<span style="color:#5b5">' . $node . '</span>';});

echo $parsed;
//<span style="font-weight: bold;">if</span> (<span style="color:#b55;">$x</span> < <span style="color:#b55;">$y</span>) echo <span style="color:#5b5">'if $x echo'</span>

Generalnie podejście 1-sze ma takie zalety że:

  • jest wydajniejsze (zwłaszcza jeśli chciałbyś robić np edytor z kolorowaniem to możesz przechowywać w cache stan dla początku każdej linii)
  • tekst nie musi być poprawnym kodem (nie musi należeć do gramatyki)

2-gie:

  • jest bardziej czytelne
  • łatwiej rozszerzalne
  • ilość błędów które popełnisz będzie mniejsza

1 użytkowników online, w tym zalogowanych: 0, gości: 1