Parser.php (3187B)
1 <?php 2 /* 3 * This file is part of the Diff package. 4 * 5 * (c) Sebastian Bergmann <sebastian@phpunit.de> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11 namespace SebastianBergmann\Diff; 12 13 /** 14 * Unified diff parser. 15 * 16 * @package Diff 17 * @author Sebastian Bergmann <sebastian@phpunit.de> 18 * @author Kore Nordmann <mail@kore-nordmann.de> 19 * @copyright Sebastian Bergmann <sebastian@phpunit.de> 20 * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 21 * @link http://www.github.com/sebastianbergmann/diff 22 */ 23 class Parser 24 { 25 /** 26 * @param string $string 27 * @return Diff[] 28 */ 29 public function parse($string) 30 { 31 $lines = preg_split('(\r\n|\r|\n)', $string); 32 $lineCount = count($lines); 33 $diffs = array(); 34 $diff = null; 35 $collected = array(); 36 37 for ($i = 0; $i < $lineCount; ++$i) { 38 if (preg_match('(^---\\s+(?P<file>\\S+))', $lines[$i], $fromMatch) && 39 preg_match('(^\\+\\+\\+\\s+(?P<file>\\S+))', $lines[$i + 1], $toMatch)) { 40 if ($diff !== null) { 41 $this->parseFileDiff($diff, $collected); 42 $diffs[] = $diff; 43 $collected = array(); 44 } 45 46 $diff = new Diff($fromMatch['file'], $toMatch['file']); 47 ++$i; 48 } else { 49 if (preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) { 50 continue; 51 } 52 $collected[] = $lines[$i]; 53 } 54 } 55 56 if (count($collected) && ($diff !== null)) { 57 $this->parseFileDiff($diff, $collected); 58 $diffs[] = $diff; 59 } 60 61 return $diffs; 62 } 63 64 /** 65 * @param Diff $diff 66 * @param array $lines 67 */ 68 private function parseFileDiff(Diff $diff, array $lines) 69 { 70 $chunks = array(); 71 72 foreach ($lines as $line) { 73 if (preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) { 74 $chunk = new Chunk( 75 $match['start'], 76 isset($match['startrange']) ? max(1, $match['startrange']) : 1, 77 $match['end'], 78 isset($match['endrange']) ? max(1, $match['endrange']) : 1 79 ); 80 81 $chunks[] = $chunk; 82 $diffLines = array(); 83 continue; 84 } 85 86 if (preg_match('/^(?P<type>[+ -])?(?P<line>.*)/', $line, $match)) { 87 $type = Line::UNCHANGED; 88 89 if ($match['type'] == '+') { 90 $type = Line::ADDED; 91 } elseif ($match['type'] == '-') { 92 $type = Line::REMOVED; 93 } 94 95 $diffLines[] = new Line($type, $match['line']); 96 97 if (isset($chunk)) { 98 $chunk->setLines($diffLines); 99 } 100 } 101 } 102 103 $diff->setChunks($chunks); 104 } 105 }