Conselhos para implementar o simples regex (para análise bbcode/geshi)
-
25-09-2019 - |
Pergunta
Eu fiz um software de anotação pessoal no PHP para que eu possa armazenar e organizar minhas anotações e desejei um bom formato simples para escrevê -las.
Eu tinha feito isso no Markdown, mas achei um pouco confuso e não havia destaque simples de sintaxe, então fiz o BBCode antes e desejei implementar isso.
Agora, para Geshi que eu realmente desejo implementar (o marcador de sintaxe), requer o código mais simples como este:
$geshi = new GeSHi($sourcecode, $language);
$geshi->parse_code();
Agora, essa é a parte mais fácil, mas o que desejo fazer é permitir que meu BBCode o chamasse.
Minha expressão regular atual para corresponder a um [sintaxe = cpp] [/sintaxe] bbcode é o seguinte:
preg_replace('#\[syntax=(.*?)\](.*?)\[/syntax\]#si' , 'geshi(\\2,\\1)????', text);
Você notará que eu captura o idioma e o conteúdo, como diabos eu o conectaria ao código GESHI?
Preg_replace parece ser capaz de substituí -lo por uma string e não uma 'expressão', não tenho certeza de como usar essas duas linhas de código para Geshi lá em cima com os dados capturados.
Estou realmente empolgado com este projeto e desejo superar isso.
Solução
Eu escrevi esta aula há algum tempo, o motivo da aula era permitir fácil personalização / análise. Talvez um pouco de exagero, mas funcione bem e eu precisava disso para o meu aplicativo. O uso é bem simples:
$geshiH = new Geshi_Helper();
$text = $geshiH->geshi($text); // this assumes that the text should be parsed (ie inline syntaxes)
---- OU ----
$geshiH = new Geshi_Helper();
$text = $geshiH->geshi($text, $lang); // assumes that you have the language, good for a snippets deal
Eu tive que fazer algum corte de outros itens personalizados que tinha, mas sem erros de sintaxe do corte que ele deve funcionar. Sinta-se livre para usá-lo.
<?php
require_once 'Geshi/geshi.php';
class Geshi_Helper
{
/**
* @var array Array of matches from the code block.
*/
private $_codeMatches = array();
private $_token = "";
private $_count = 1;
public function __construct()
{
/* Generate a unique hash token for replacement) */
$this->_token = md5(time() . rand(9999,9999999));
}
/**
* Performs syntax highlights using geshi library to the content.
*
* @param string $content - The context to parse
* @return string Syntax Highlighted content
*/
public function geshi($content, $lang=null)
{
if (!is_null($lang)) {
/* Given the returned results 0 is not set, adding the "" should make this compatible */
$content = $this->_highlightSyntax(array("", strtolower($lang), $content));
}else {
/* Need to replace this prior to the code replace for nobbc */
$content = preg_replace('~\[nobbc\](.+?)\[/nobbc\]~ie', '\'[nobbc]\' . strtr(\'$1\', array(\'[\' => \'[\', \']\' => \']\', \':\' => \':\', \'@\' => \'@\')) . \'[/nobbc]\'', $content);
/* For multiple content we have to handle the br's, hence the replacement filters */
$content = $this->_preFilter($content);
/* Reverse the nobbc markup */
$content = preg_replace('~\[nobbc\](.+?)\[/nobbc\]~ie', 'strtr(\'$1\', array(\'&#91;\' => \'[\', \'&#93;\' => \']\', \'&#58;\' => \':\', \'&#64;\' => \'@\'))', $content);
$content = $this->_postFilter($content);
}
return $content;
}
/**
* Performs syntax highlights using geshi library to the content.
* If it is unknown the number of blocks, use highlightContent
* instead.
*
* @param string $content - The code block to parse
* @param string $language - The language to highlight with
* @return string Syntax Highlighted content
* @todo Add any extra / customization styling here.
*/
private function _highlightSyntax($contentArray)
{
$codeCount = $contentArray[1];
/* If the count is 2 we are working with the filter */
if (count($contentArray) == 2) {
$contentArray = $this->_codeMatches[$contentArray[1]];
}
/* for default [syntax] */
if ($contentArray[1] == "")
$contentArray[1] = "php";
/* Grab the language */
$language = (isset($contentArray[1]))?$contentArray[1]:'text';
/* Remove leading spaces to avoid problems */
$content = ltrim($contentArray[2]);
/* Parse the code to be highlighted */
$geshi = new GeSHi($content, strtolower($language));
return $geshi->parse_code();
}
/**
* Substitute the code blocks for formatting to be done without
* messing up the code.
*
* @param array $match - Referenced array of items to substitute
* @return string Substituted content
*/
private function _substitute(&$match)
{
$index = sprintf("%02d", $this->_count++);
$this->_codeMatches[$index] = $match;
return "----" . $this->_token . $index . "----";
}
/**
* Removes the code from the rest of the content to apply other filters.
*
* @param string $content - The content to filter out the code lines
* @return string Content with code removed.
*/
private function _preFilter($content)
{
return preg_replace_callback("#\s*\[syntax=(.*?)\](.*?)\[/syntax\]\s*#siU", array($this, "_substitute"), $content);
}
/**
* Replaces the code after the filters have been ran.
*
* @param string $content - The content to replace the code lines
* @return string Content with code re-applied.
*/
private function _postFilter($content)
{
/* using dashes to prevent the old filtered tag being escaped */
return preg_replace_callback("/----\s*" . $this->_token . "(\d{2})\s*----/si", array($this, "_highlightSyntax"), $content);
}
}
?>
Outras dicas
Parece -me que você já acertou a regex. Seu problema está na invocação, por isso sugiro fazer uma função de invólucro:
function geshi($src, $l) {
$geshi = new GeSHi($sourcecode, $language);
$geshi->parse_code();
return $geshi->how_do_I_get_the_results();
}
Agora, isso normalmente seria suficiente, mas é provável que o código -fonte contenha citações únicas ou de Dobule. Portanto, você não pode escrever preg_replace(".../e", "geshi('$2','$1')", ...)
como você precisaria. (Observe que '$ 1' e '$ 2' precisam de cotações porque o Preg_replace apenas substitui os espaços reservados de US $ 1 e US $ 2, mas isso precisa ser um código em linha PHP válido).
É por isso que você precisa usar preg_replace_callback
Para evitar problemas de escapar no código de substituição do /E Exec. Por exemplo:
preg_replace_callback('#\[syntax=(.*?)\](.*?)\[/syntax\]#si' , 'geshi_replace', $text);
E eu faria um segundo invólucro, mas você pode combiná -lo com o código original:
function geshi_replace($uu) {
return geshi($uu[2], $uu[1]);
}
Use preg_match:
$match = preg_match('#\[syntax=(.*?)\](.*?)\[/syntax\]#si', $text);
$geshi = new GeSHi($match[2], $match[1]);