0) { $result[] = self::formatOrderedList($listItems); $listItems = array(); $inOrderedList = false; } $result[] = ''; continue; } // Check if this is an ordered list item (starts with "1. ", "2. ", etc.) if (self::isOrderedListItem($trimmed)) { if (!$inOrderedList) { $inOrderedList = true; $listItems = array(); } // Extract text after the number $listItems[] = self::extractListItemText($trimmed); } else { // Flush any pending list before processing non-list line if ($inOrderedList && count($listItems) > 0) { $result[] = self::formatOrderedList($listItems); $listItems = array(); $inOrderedList = false; } // Process regular line $formatted = self::formatLine($trimmed); $result[] = $formatted; } } // Flush any remaining list if ($inOrderedList && count($listItems) > 0) { $result[] = self::formatOrderedList($listItems); } // Join with line breaks $html = implode('
', $result); // Clean up excessive line breaks $html = preg_replace('/


+/', '

', $html); return $html; } /** * Check if a line is an ordered list item (e.g., "1. text") */ private static function isOrderedListItem($line) { return preg_match('/^\d+\.\s+/', $line) === 1; } /** * Extract the text part of a list item, removing the number */ private static function extractListItemText($line) { $matches = array(); if (preg_match('/^\d+\.\s+(.*)$/', $line, $matches)) { return isset($matches[1]) ? $matches[1] : $line; } return $line; } /** * Convert an array of list items to HTML ordered list */ private static function formatOrderedList($items) { if (count($items) === 0) { return ''; } $html = '
    '; foreach ($items as $item) { $html .= '
  1. ' . $item . '
  2. '; } $html .= '
'; return $html; } /** * Format a single line - mainly applying bold to key labels */ private static function formatLine($line) { // Match "Key: value" pattern if (preg_match('/^([^:]+):\s*(.*)$/', $line, $matches)) { $key = $matches[1]; $value = isset($matches[2]) ? $matches[2] : ''; // Check if this key should be bolded if (self::shouldBoldKey($key)) { $line = '' . htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . ': ' . $value; } } // Apply italics to specific phrases $line = self::applyItalics($line); return $line; } /** * Determine if a key should be bolded (heuristic) */ private static function shouldBoldKey($key) { $key = trim($key); // List of known keys that should be bolded $knownKeys = array( 'Item Code' => true, 'Item Description' => true, 'Type' => true, 'Cable Length' => true, 'Ui' => true, 'li' => true, 'Li, Ci' => true, 'II 2G' => true, 'II 2D' => true, 'IBEx' => true, 'Includes' => true, 'With standard' => true, 'See attached' => true, 'Testing at' => true, ); // Check exact matches if (isset($knownKeys[$key])) { return true; } // Check partial matches for common patterns $lowerKey = strtolower($key); $commonPatterns = array( 'code', 'description', 'type', 'cable', 'temperature', 'pressure', 'includes', 'testing', ); foreach ($commonPatterns as $pattern) { if (strpos($lowerKey, $pattern) !== false) { return true; } } return false; } /** * Apply italic formatting to specific phrases */ private static function applyItalics($line) { $italicPatterns = array( 'See attached EC Conformity Declaration for the SE Sensor', 'If Insulated panels are used', ); foreach ($italicPatterns as $pattern) { if (strpos($line, $pattern) !== false) { $escapedPattern = htmlspecialchars($pattern, ENT_QUOTES, 'UTF-8'); $line = str_replace($escapedPattern, '' . $escapedPattern . '', $line); } } return $line; } } ?>