3

I have been working on a markdown converter today for a project of mine. I got lost in it and just ran through the code and noticed I had a huge amount for converting lists. My code is below , I have just supplied the code that deals with lists, I could really do with some suggestions on shortening the code, I just cant see past what I have written and need a fresh pair of eyes.

<?php

class Markdown {

  private static $html = '';
  private static $list_types = array(
    array(
      '>>',
      '<ul>',
      '</ul>'
    ),
    array(
      '>>>',
      '<ol>',
      '</ol>'
    )
  );
  private static $list_patterns = array(
    '/-[ ]+(.+)/' => ' >>\1',
    '/[0-9]{1}\. (.+)/' => ' >>>\1'
  );

  public static function convertText($markdown = array()) {
    $markdown = explode("\n", strip_tags($markdown));
    foreach ($markdown as &$line) {
      $line = htmlentities($line, ENT_QUOTES, 'UTF-8');
      foreach (self::$list_patterns as $pattern => $replace) {
        if (!is_array($line) && preg_match($pattern, $line)) {
          $para = false;
          $line = preg_replace($pattern, $replace, $line);
          $type = 0;
          foreach (self::$list_types as $key => $val) {
            if (preg_match('/ ' . $val[0] . ' /', $line))
              $type = $key;
          }
          $line = preg_split('/' . self::$list_types[$type][0] . '/', $line);
          $line = array('depth' => strlen($line[0]), 'string' => $line[1], 'type' => $type);
        }
      }
    }

    while (!empty($markdown)) {
      $snippet = array_shift($markdown);
      if (is_array($snippet))
        self::makeList($snippet, $markdown);
      else
        self::$html .= $snippet;
    }
    return self::$html;
  }

  private static function makeList($snippet, &$markdown, $last_depth = 0, $close_tag = '') {
    if ($last_depth == $snippet['depth'])
      self::$html .= sprintf('</li><li>%s', $snippet['string']);
    elseif ($last_depth < $snippet['depth'])
      self::$html .= sprintf('%s<li>%s', self::$list_types[$snippet['type']][1], $snippet['string']);
    elseif ($last_depth > $snippet['depth'])
      self::$html .= sprintf('</li>%s<li>%s', $close_tag, $snippet['string']);

    $next_snippet = array_shift($markdown);
    if (is_array($next_snippet))
      self::makeList($next_snippet, $markdown, $snippet['depth'], self::$list_types[$snippet['type']][2]);
    else
      array_unshift($markdown, $next_snippet);

    self::$html .= sprintf('</li>%s', $close_tag);
  }

}

?>

Basically the code does lots of pattern matching and for any patterns except list it will leave as a string in the array "$markdown", for lists it creates an array with the list type, depth and string. There fore at the end of the text conversion I can loop through the "$markdown" array and build the nested loop structure by checking if the next item is an array or not.

Sorry if the question seems vague, its not ment to be, I just want some hint on how to shorten my code as it seems like I have written loads.

Thanks in advance

Luke

6
  • 9
    You realize there's already a complete PHP markdown implementation in the wild? It's licensed BSD/GPL (what you prefer) so embedding it on your software shouldn't be a problem. michelf.com/projects/php-markdown Commented Nov 30, 2010 at 22:50
  • What @thief said. Unless you're really interested in wheels, don't reinvent them. Commented Nov 30, 2010 at 23:37
  • I have looked at this class and after removing all of the unnecessary stuff for me (I dont need the wordpress stuff etc) its still 1500 lines of code. I know that there is a great deal of commenting in those 1500 lines but I was just hoping that it was achievable in a smaller package. And this kind of wheel does hold some interest for me. Thanks for the comments though. Commented Dec 1, 2010 at 0:03
  • 1
    @El Yobo Actually, they are using a whole bunch of regexes. Markdown is a surprisingly bad standard (but an awesome format). Agreed on the 1500 lines though. You may be hard pressed to come up with anything shorter. Commented Dec 1, 2010 at 2:32
  • 1
    @Luke Don't worry about 1500 lines of code, worry about building an awesome product. Don't be concerned with: c2.com/cgi/wiki?PrematureOptimization Best of luck! Commented May 16, 2012 at 21:54

2 Answers 2

2

@Theifmaster is probably a better way forward. But, I managed to remove 2 lines of code, and the unused variable $para;

<?php

class Markdown {

  private static $html = '';
  private static $list_types = array(
    array('>>','<ul>','</ul>'),
    array('>>>','<ol>','</ol>')
  );
  private static $list_patterns = array(
    '/-[ ]+(.+)/' => ' >>\1',
    '/[0-9]{1}\. (.+)/' => ' >>>\1'
  );

  public static function convertText($markdown = array()) {
    foreach (explode("\n", strip_tags($markdown)) as &$line) {
      $line = htmlentities($line, ENT_QUOTES, 'UTF-8');
      foreach (self::$list_patterns as $pattern => $replace) {
        if (!is_array($line) && preg_match($pattern, $line)) {
          $line = preg_replace($pattern, $replace, $line);
          $type = 0;
          foreach (self::$list_types as $key => $val) {
            if (preg_match('/ ' . $val[0] . ' /', $line))
              $type = $key;
          }
          $line = preg_split('/' . self::$list_types[$type][0] . '/', $line);
          $line = array('depth' => strlen($line[0]), 'string' => $line[1], 'type' => $type);
        }
      }
    }

    while (!empty($markdown)) {
      $snippet = array_shift($markdown);
      if (is_array($snippet))
        self::makeList($snippet, $markdown);
      else
        self::$html .= $snippet;
    }
    return self::$html;
  }

  private static function makeList($snippet, &$markdown, $last_depth = 0, $close_tag = '') {
    if ($last_depth == $snippet['depth'])
      self::$html .= sprintf('</li><li>%s', $snippet['string']);
    elseif ($last_depth < $snippet['depth'])
      self::$html .= sprintf('%s<li>%s', self::$list_types[$snippet['type']][1], $snippet['string']);
    elseif ($last_depth > $snippet['depth'])
      self::$html .= sprintf('</li>%s<li>%s', $close_tag, $snippet['string']);

    $next_snippet = array_shift($markdown);
    if (is_array($next_snippet))
      self::makeList($next_snippet, $markdown, $snippet['depth'], self::$list_types[$snippet['type']][2]);
    else
      array_unshift($markdown, $next_snippet);

    self::$html .= sprintf('</li>%s', $close_tag);
  }

}

enjoy

Sign up to request clarification or add additional context in comments.

Comments

0

As @Theifmaster said, michelf.com/projects/php-markdown is already comprehensive and awesome so I ended up using it as I really was not going to manage to add anything more useful to it. Good learning experience though starting to write the code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.