regexpowershelldatetime

Function for producing a regex pattern from a Date and Time string


I have a PowerShell script that scans a line of text for a given regex pattern, corresponding to a Date and/or Time, and extracts the Date/Time string for further processing.

Example:

#List of user inputs
$dateformat = 'M/d/yyyy,HH:mm:ss.fff'
$regexFormat = '\d{1,2}\/\d{1,2}\/\d{4}\,\d{1,2}\:\d{1,2}\:\d{1,2}\.\d{3}'`

The script then searches for that regex pattern in a line of input text, e.g.

$input = '6/5/2025,08:37:38.058,1.0527,-39.5013,38.072,1.0527,-39.5013'

The script works well, but currently requires the user to build the regex pattern manually. I am targeting this tool for users who don't need to have PowerShell or coding experience.

My goal is to add a function to methodically build up a regex pattern given only an example format user input such as

$formatinput1 = 'M/d/yyyy,HH:mm:ss.fff'
$formatinput2 = 'yyyy-MM-dd,HH:mm:ss'
$formatinput3 = 'yyyy-MM-dd hh:mm:ss [A|P]M'

or else a sample string user input

$sampleinput1 = '6/5/2025,08:37:38.058'
$sampleinput2 = '2025-06-05,08:37:38'
$sampleinput3 = '2025-6-5 8:37:38 AM'

The user would give the example string as an input, and the function would build up a corresponding regex pattern to use in the text search.

My current thought is to simply create a look-up table of regex formats for all of the most common date formats (and update it when I come across a new one).

But I am wondering if there is a more methodical way?


Solution

  • Here is a pretty simple regex pattern generator. My approach is really simple, just parsing the end user suitable input string like yyyy-MM-dd,HH:mm:ss or 2025-06-05,08:37:38 and building a new regex pattern by exchanging all chars or digits by \d or escaping some chars like ., / or \.

    The main issue was to correctly handle the specific [A|P]M pattern, but I think it should be OK. Honestly, it is not super perfect, but fine for getting a clue how it could be done.

    Please let me know if you need further explanations about my code and I will add it here tomorrow.

    function new-regex-pattern {
        param (
            [string]$s
        )
        $ampm = '[A|P]M'
        if (($s -match [Regex]::Escape($ampm)) -or ($s -match $ampm)) {
            $regexOptions = [Text.RegularExpressions.RegexOptions]'IgnoreCase, CultureInvariant'
            if ($s -match [Regex]::Escape($ampm)) {
                $pattern = -join ('(?<start>.*)(?<AM_PM>', 
                  [Regex]::Escape($ampm), ')(?<end>.*)')
            }
            else {
                $pattern = -join ('(?<start>.*)(?<AM_PM>', $ampm, ')(?<end>.*)')
            }
            $regexPattern = [Regex]::new($pattern, $regexOptions)
            $match = $regexPattern.Matches($s)
            return (convert-pattern $match[0].Groups['start'].Value) + 
              $match[0].Groups['AM_PM'].Value + 
              (convert-pattern $match[0].Groups['end'].Value)
        }
        return convert-pattern $s
    }
    
    function convert-pattern {
        param (
            [string]$s
        )
        if ($s.Length -gt 0) {
            foreach ($c in [char[]]$s) {
                switch ($c) {
                    { $_ -match '[A-Z0-9]' } { $result += '\d' }
                    { $_ -match '\s' } { $result += '\s' }
                    { $_ -eq '.' } { $result += '\.' }
                    { $_ -eq '/' } { $result += '\/' }
                    { $_ -eq '\' } { $result += '\\' }
                    default { $result += $_ }
                }
            }
        }
        return $result
    }
    
    $formatinput1 = 'M/d/yyyy,HH:mm:ss.fff'
    $formatinput2 = 'yyyy-MM-dd,HH:mm:ss'
    $formatinput3 = 'yyyy-M-d h:mm:ss [A|P]M'
    
    $sampleinput1 = '6/5/2025,08:37:38.058'
    $sampleinput2 = '2025-06-05,08:37:38'
    $sampleinput3 = '2025-6-5 8:37:38 AM'
    
    $example1 = '6/5/2025,08:37:38.058,1.0527,-39.5013,38.072,1.0527,-39.5013'
    $example2 = '2025-06-05,08:37:38,1.0527,-39.5013,38.072,1.0527,-39.5013'
    $example3 = '2025-6-5 8:37:38 AM,1.0527,-39.5013,38.072,1.0527,-39.5013'
    
    $regexPattern = [Regex]::new((new-regex-pattern $formatinput1))
    Write-Host $regexPattern.Matches($example1)
    
    $regexPattern = [Regex]::new((new-regex-pattern $formatinput2))
    Write-Host $regexPattern.Matches($example2)
    
    $regexPattern = [Regex]::new((new-regex-pattern $formatinput3))
    Write-Host $regexPattern.Matches($example3)
    
    $regexPattern = [Regex]::new((new-regex-pattern $sampleinput1))
    Write-Host $regexPattern.Matches($example1)
    
    $regexPattern = [Regex]::new((new-regex-pattern $sampleinput2))
    Write-Host $regexPattern.Matches($example2)
    
    $regexPattern = [Regex]::new((new-regex-pattern $sampleinput3))
    Write-Host $regexPattern.Matches($example3)