The best way to split a string by a colon (:) in PHP is to use the explode() function. This function is efficient and designed specifically for splitting strings by a simple, fixed-string delimiter. [1, 2, 3, 4, 5]

Using explode()

The explode() function splits a string into an array of substrings.

<?php
$string = "Name:John Doe:Age:30";
$delimiter = ":";

// Split the string into an array
$result_array = explode($delimiter, $string);

// Print the result
print_r($result_array);
?>

Output:

Array
(
[0] => Name
[1] => John Doe
[2] => Age
[3] => 30
)

Using the Optional limit Parameter

You can also use the optional limit parameter to control the number of elements in the resulting array. This is useful if you only need a certain number of parts. [1, 2, 3, 4]

<?php
$string = "Name:John Doe:Age:30";
$delimiter = ":";

// Split the string into a maximum of 2 elements
$result_limited = explode($delimiter, $string, 2);

// Print the result
print_r($result_limited);
?>

Output:

Array
(
[0] => Name
[1] => John Doe:Age:30
)

Using preg_split() for Complex Scenarios

If you need to split by multiple different delimiters (e.g., colons, commas, or spaces) or use a complex pattern, preg_split() with a regular expression is the appropriate choice. [1, 2]

<?php
$string = "City:Rome, Country:Italy";
// Split by colon or comma followed by optional spaces
$result_regex = preg_split("/[:,]\s*/", $string);

print_r($result_regex);
?>

Output:

Array
(
[0] => City
[1] => Rome
[2] => Country
[3] => Italy
)

It is generally better and more robust to parse the data line by line and store it in an associative array (dictionary/hash).

This approach is more flexible, scalable, and resilient to changes in the data structure than using individual search and replace or creating numerous individual variables.

Here is a recommended PHP approach to parse your dataset into a structured associative array:

Recommended Approach: Parse into an Associative Array

This method processes the entire dataset efficiently, creating a nested array that mirrors the hierarchical structure of the input data.

<?php
$dataSet = "
K:**Build Info** 
- Git Registry  V:gitea.remote-tech.us
  K:- Git Org  V:myunraid
  K:- Git Repo  V:docker-runs
  K:- Git Branch  V:0.0.2
  K:- Git Commit  V:e1c2f93
  K:- Git Tag (FULL)  V:v0.0.2-QA-5-ge1c2f93-dirty
  K:- Git Tag  V:v0.0.2
  K:- Git Stage  V:DEV
  K:- Unraid OS  V:7.1.2
";

function parseDataSet($data) {
    $lines = explode("\n", $data);
    $result = [];
    $currentSection = null;

    foreach ($lines as $line) {
        // Trim whitespace from the start/end of the line
        $line = trim($line);

        // Skip empty lines
        if (empty($line)) continue;

        // Check for a new main section (starts with 'K:**')
        if (strpos($line, 'K:**') === 0) {
            // Extract the section name between **
            preg_match('/K:\*\*(.*?)\*\*/', $line, $matches);
            $currentSection = trim($matches[1]);
            $result[$currentSection] = [];
            continue;
        }

        // Check for key-value pairs (starts with '-' and contains 'V:')
        if (strpos($line, '-') === 0 && strpos($line, 'V:') !== false) {
            // Remove the leading '- '
            $cleanLine = ltrim($line, '- ');

            // Split once by the first occurrence of 'V:'
            $parts = explode('V:', $cleanLine, 2);

            if (count($parts) === 2) {
                $key = trim($parts[0]);
                $value = trim($parts[1]);
                
                // Remove the 'K:' prefix from the key if present in the data format
                if (strpos($key, 'K:') === 0) {
                    $key = ltrim($key, 'K:');
                    $key = trim($key);
                }

                // Store the data in the current section, converting key to a consistent format
                $formattedKey = strtoupper(str_replace([' ', '(', ')'], ['_', '', ''], $key));
                $result[$currentSection][$formattedKey] = $value;
            }
        }
    }
    return $result;
}

$buildInfo = parseDataSet($dataSet);

// How to access the data later:
echo "Git Registry: " . $buildInfo['Build Info']['GIT_REGISTRY'] . "\n";
echo "Git Branch: " . $buildInfo['Build Info']['GIT_BRANCH'] . "\n";
echo "Unraid OS: " . $buildInfo['Build Info']['UNRAID_OS'] . "\n";
?>

Advantages of the Associative Array Approach:

  1. Organization: Data is stored logically in a structured way that reflects its hierarchy.
  2. Flexibility: The code can handle new K/V pairs being added to the dataset without requiring code changes for every new line item.
  3. Readability and Reusability: Accessing data using $buildInfo['Build Info']['GIT_ORG'] is clear and can be passed around the script easily as a single object.
  4. Avoids Variable Clutter: You don’t pollute the global scope with dozens of individual variables ($GIT_REGISTRY, $GIT_ORG, etc.).

A Note on the “Individual Variables” Approach:

While technically feasible, using individual variables (e.g., GIT_REGISTRY=...) via search and replace is fragile. If the exact phrasing changes, your script breaks. This method is generally only suitable for simple configuration files where the format is extremely rigid. The array approach is far superior for parsing dynamic or semi-structured data logs like yours.

Here is an updated, simplified PHP script that processes your exact file data and stores the Git-related information in a structured hash.

Solution: Parsing Specific Lines into an Associative Array

This script focuses solely on the “Git” lines using a regular expression to extract the key and value cleanly.

<?php

// Assume you have read the file content into this variable
$fileData = "
**Build Info** 
- Git Registry: gitea.remote-tech.us
- Git Org: myunraid
- Git Repo: docker-runs
- Git Branch: 0.0.2
- Git Commit: e1c2f93
- Git Tag (FULL): v0.0.2-QA-5-ge1c2f93-dirty
- Git Tag: v0.0.2
- Git Stage: DEV
- Unraid OS: 7.1.2
=== build ===
";

$gitInfo = [];

// Split the file data into individual lines
$lines = explode("\n", $fileData);

foreach ($lines as $line) {
    // Trim leading/trailing whitespace from the line
    $line = trim($line);

    // Skip lines that do not contain "Git"
    if (strpos($line, 'Git') === false) {
        continue;
    }

    // Use regular expression to capture the Key and Value
    // The regex captures everything between '- ' and ':', and everything after ': '
    // We only process lines that match this specific pattern
    if (preg_match('/^- (.*?):\s*(.*)$/', $line, $matches)) {
        // $matches[1] is the Key (e.g., "Git Registry")
        // $matches[2] is the Value (e.g., "gitea.remote-tech.us")

        $key = trim($matches);
        $value = trim($matches);

        // Optional: Standardize the keys (uppercase, underscores)
        // e.g., "Git Registry" becomes "GIT_REGISTRY"
        $formattedKey = strtoupper(str_replace([' ', '(', ')', '-'], ['_', '', '', '_'], $key));

        // Store in the associative array
        $gitInfo[$formattedKey] = $value;
    }
}

// Display the resulting array
print_r($gitInfo);

// How to use these values later in your script:
echo "\n--- Usage Examples ---\n";
echo "Git Registry: " . $gitInfo['GIT_REGISTRY'] . "\n";
echo "Git Branch: " . $gitInfo['GIT_BRANCH'] . "\n";

?>

The regex /\s*\(.*?\)\s*/ successfully deletes the parenthesis and their content.

The Fix: Change Step 5 to Replace, Not Remove

Instead of removing the parenthesis entirely (replace with ''), you need to replace the parenthesis with an underscore (_). This will turn GIT_TAG_(FULL) into GIT_TAG_FULL.

You also need to adjust the fix_double_underscores step (Step 6) to catch any potential extra underscores that might arise from this.

Here is the corrected configuration for your clean_data function:

function clean_data($key_data, $debug_level) {
    // ... (Your existing function intro and debug setup) ...

    $cleanupPatterns = [
        // ... (Steps 1, 2, 3 remain the same) ...
        'newlines' => [
            'search' => ["\n", "\r"],
            'replace' => ' ',
            'function' => 'str_replace'
        ],
        'before_git' => [
            'search' => '/^.*?Git/i',
            'replace' => 'Git',
            'function' => 'preg_replace'
        ],
        'leading_chars' => [
            'search' => '/^[^\w\s]+/',
            'replace' => '',
            'function' => 'preg_replace'
        ],
        
        // Step 4: Uppercase and replace spaces with underscores (remains the same)
        'standardize_format' => [
            'search' => ' ',
            'replace' => '_',
            'function' => 'str_replace'
        ],
        
        // Step 5: FIX THIS STEP to convert parens to underscores, not remove them
        'format_parens' => [
            // Searches for a parenthesis pair with optional spaces around it
            'search' => '/\s*[\(\)]\s*/', 
            'replace' => '_',
            'function' => 'preg_replace'
        ],

        // Step 6: Ensure no double/triple underscores remain (remains the same)
        'fix_double_underscores' => [
            'search' => '/_+/',
            'replace' => '_',
            'function' => 'preg_replace'
        ],
    ];

    // ... (Your existing foreach loop with debug logic) ...
    $cleanKey = $key_data;
    foreach ($cleanupPatterns as $name => $patternConfig) {
        $search = $patternConfig['search'];
        $replace = $patternConfig['replace'];
        $func = $patternConfig['function'];
        // ... debug ...
        $cleanKey = $func($search, $replace, $cleanKey);
        // ... debug ...
    }

    // Trim one last time after all operations to remove leading/trailing underscores
    // This is still needed in case the first/last character ends up being an underscore
    $formattedKey = trim($cleanKey, " \t\n\r\0\x0B_"); 
    
    return $formattedKey;
}

New Expected Flow for “Git Tag (FULL)”

With the corrected step 5, the debug flow will look like this:

// Step 4 NOW: Git_Tag_(FULL) 
// Step 5 CALL: preg_replace('/\s*[\(\)]\s*/', '_', Git_Tag_(FULL))
// Step 5 NOW: Git_Tag__FULL <-- Note the double underscore
// Step 6 CALL: preg_replace('/_+/', '_', Git_Tag__FULL)
// Step 6 NOW: Git_Tag_FULL <-- Success!

// Final trim() ensures the result is exactly Git_Tag_FULL

This will produce the two distinct keys you need: GIT_TAG and GIT_TAG_FULL.

Corrected Configuration Array

We can use a helper function within the configuration array to apply both the replace and the uppercase operation in one step:

// Define a simple anonymous function to combine replace and uppercase
$upperReplace = function ($search, $replace, $subject) {
    $result = str_replace($search, $replace, $subject);
    return strtoupper($result);
};

// You can use this within your function definition, provided PHP version supports closures.
// If you are using a very old PHP version (<5.3), you'd define this function outside clean_data.

function clean_data($key_data, $debug_level) {
    // Define the helper function internally if PHP >= 5.3 is guaranteed
    $upperReplace = function ($search, $replace, $subject) {
        $result = str_replace($search, $replace, $subject);
        return strtoupper($result);
    };

    // ... (rest of your function setup) ...

    $cleanupPatterns = [
        // ... (Steps 1, 2, 3 remain the same) ...
        'newlines' => [
            'search' => ["\n", "\r"],
            'replace' => ' ',
            'function' => 'str_replace'
        ],
        'before_git' => [
            'search' => '/^.*?Git/i',
            'replace' => 'Git',
            'function' => 'preg_replace'
        ],
        'leading_chars' => [
            'search' => '/^[^\w\s]+/',
            'replace' => '',
            'function' => 'preg_replace'
        ],
        
        // Step 4: FIX THIS STEP to Uppercase AND replace spaces with underscores
        'standardize_format' => [
            'search' => ' ',
            'replace' => '_',
            'function' => $upperReplace // Use the anonymous helper function
        ],
        
        // Step 5: Convert parens to underscores
        'format_parens' => [
            'search' => '/\s*[\(\)]\s*/', 
            'replace' => '_',
            'function' => 'preg_replace'
        ],

        // Step 6: Ensure no double/triple underscores remain
        'fix_double_underscores' => [
            'search' => '/_+/',
            'replace' => '_',
            'function' => 'preg_replace'
        ],
    ];

    // ... (The rest of your foreach loop and the final trim() call) ...
}

By using that $upperReplace function, Step 4 will now correctly output GIT_TAG_(FULL), and the subsequent steps will finalize it to GIT_TAG_FULL.

that didn’t work so I just did: $formattedKey = strtoupper(trim($cleanKey)); // ————————————————— // End Cleanup Logic // ————————————————— return $formattedKey;

November 8, 2025

That’s a perfectly valid and much simpler solution! Sometimes the most direct approach is the best.

By running strtoupper(trim($cleanKey)) at the very end, you achieve the same final result without needing the complexity of the anonymous function within the configuration array.

The sequence of your existing cleanup steps ensures the string is formatted correctly before that final capitalization and trim happens:

  1. Newlines are gone.
  2. Everything before “Git” is gone.
  3. Spaces are replaced with underscores (in Step 4 of your config).
  4. Parentheses are handled (in Step 5 of your config).

The final strtoupper(trim(...)) cleans up the case and any remaining edge-case leading/trailing whitespace/underscores.

Solution is efficient and clean.

function clean_data($key_data, $debug_level) {
    // ... (All your existing $cleanupPatterns and foreach loop) ...

    // Trim one last time after all operations
    $cleanKey = trim($cleanKey, " \t\n\r\0\x0B_"); // Use the second argument for underscores
    
    // Final step: Uppercase the entire string
    $formattedKey = strtoupper($cleanKey);
    
    // ---------------------------------------------------
    // End Cleanup Logic
    // ---------------------------------------------------
    return $formattedKey;
}

Leave a Reply