TM-DataManipulation.psm1
using namespace System.Collections.Generic class Range { <# .SYNOPSIS A class to hold the start/end data for a given contiguous integer range. #> [long]$Start [long]$End # Default New Values Range() { $this.Start = ([int]::MinValue - 1) $this.End = ([int]::MaxValue + 1) } # Set Values Range([long]$Start, [long]$End) { $this.Start = $Start $this.End = $End } [string]ToString() { return ( if ($this.Start -eq $this.End) { $this.Start } else { "$($this.Start)-$($this.End)" } ) } } function Get-ContiguousRange { <# .SYNOPSIS Finds contiguous ranges of integers within a given integer array. .DESCRIPTION This function takes a list of integers and identifies contiguous ranges within the list. The output can be a list of Range objects or a string. .PARAMETER IntRange Array of integers to find contiguous ranges within .PARAMETER CombineString If selected, returns the contiguous ranges as a single comma separated string. #> [CmdletBinding()] [OutputType([List[Range]], [string])] param ( [Parameter( Position = 0, Mandatory, HelpMessage = 'Enter one or more integers.' )] [int[]]$IntRange, [Parameter( Position = 1, Mandatory = $false, HelpMessage = 'Outputs contiguous ranges as a string.' )] [switch]$CombineString ) begin { $Return = [List[Range]]::new() $RangeObj = [Range]::New() [long]$Index = 0 [long[]]$LongRange = $IntRange | Sort-Object -Unique } process { for ([long]$a = $LongRange[0]; [long]$a -le $LongRange[-1]; [long]$a++) { # Set Start value if ($RangeObj.Start -eq ([int]::MinValue - 1)) { if ($LongRange[$Index] -ne $a) { $a = $LongRange[$Index] } $RangeObj.Start = $a } # Set End Value if ( ($LongRange[$Index] -eq $a) -and ($LongRange[($Index + 1)] -ne ([long]$a + 1)) -and ($RangeObj.End -eq ([int]::MaxValue + 1)) ) { $RangeObj.End = $a $Return.Add($RangeObj) $RangeObj = [Range]::New() } $Index++ } } end { if ($CombineString) { $Strings = $Return | ForEach-Object { $_.ToString() } return $Strings -join ', ' } else { return $Return } } } class SemVer { <# .SYNOPSIS Translates a version string into a formal semantic versioning pattern. {Major}.{Minor}.{Patch}-{pre-releaseTag}+{buildNum} .DESCRIPTION Utilizes regular expressions to verify if a given string adheres to semantic versioning rules. For more details: https://semver.org/ Examples of valid semantic versions: ex0: 2.1.4 ex1: 5.12.96-pr1+000a ex2: 10.3.2+002 ex3: 3.1.0-rc3 .PARAMETER Version The version string to be parsed into a SemVer object. .OUTPUTS When the provided version does not follow semantic versioning format, the Valid field will be set to false. The Major, Minor, and Patch properties will be initialized to 0 and the PreRelease and Build properties will contain empty strings. Conversely, if the version adheres to the semantic versioning format, the Valid field will be set to true. The Major, Minor, and Patch properties will contain their respective values as [long]s. The PreRelease and Build properties will either be empty if unused, or hold the string value of the relevant fields. #> [boolean]$Valid = $false [long]$Major = 0 [long]$Minor = 0 [long]$Patch = 0 [string]$PreRelease = [string]::Empty [string]$Build = [string]::Empty SemVer( [string]$Version ) { $SemVerRegex = '^' + '(?<Major>0|[1-9]\d*)\.' + '(?<Minor>0|[1-9]\d*)\.' + '(?<Patch>0|[1-9]\d*)' + '(?:-(?<PreRelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))' + '?(?:\+(?<Build>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?' + '$' if ($Version -match $SemVerRegex) { $this.Valid = $true $this.Major = [long]::Parse($Matches['Major']) $this.Minor = [long]::Parse($Matches['Minor']) $this.Patch = [long]::Parse($Matches['Patch']) $this.PreRelease = $Matches['PreRelease'] $this.Build = $Matches['Build'] } } [string] ToString() { $result = [string]::Empty if ($this.Valid) { $result = "$($this.Major).$($this.Minor).$($this.Patch)" if ([string]::IsNullOrEmpty($this.PreRelease) -eq $false) { $result += "-$($this.PreRelease)" } if ([string]::IsNullOrEmpty($this.Build) -eq $false) { $result += "+$($this.Build)" } } return $result } } function Test-MatchesSemVer { <# .SYNOPSIS Evaluates if the provided version string adheres to semantic versioning rules. .DESCRIPTION This function checks whether the input string follows the semantic versioning format and returns the appropriate boolean value or the [SemVer] object if PassThru is selected. .PARAMETER Version The version string to be evaluated against semantic versioning rules. .PARAMETER PassThru An optional switch parameter. When selected, returns the [SemVer] object instead of a boolean. .OUTPUTS If the version string does not adhere to semantic versioning format, the function returns false. When the version string complies with semantic versioning rules, the function returns true, unless PassThru is selected. If PassThru is selected and the version string is valid, it returns the [SemVer] object. .EXAMPLE if (Test-MatchesSemVer -Version $Version) { Move-Item -Path $Csproj.FullName -Destination $PackagePath } .EXAMPLE $SemVer = Test-MatchesSemVer -Version $Version -PassThru if ($SemVer.Valid -and ($SemVer.PreRelease -eq [string]::Empty)) { dotnet nuget push $Package.FullName --api-key $ApiKey --source $NugetSource } #> [CmdletBinding()] [OutputType([Boolean], [SemVer])] param( [Parameter(Mandatory)] [string]$Version, [Parameter(Mandatory = $false)] [switch]$PassThru ) [SemVer]$SemVer = [SemVer]::new($Version) if ($SemVer.Valid) { if ($PassThru) { return $SemVer } else { return $true } } return $false } function Write-ReverseString { <# .SYNOPSIS Reverses a given string. .DESCRIPTION This function takes a string as input and reverses its characters. The output is the reversed string. .PARAMETER String The string to be reversed. .PARAMETER Encoding The encoding method to use when reversing the string. Available options are 'Utf8' and 'Utf16'. The default is 'Utf8'. #> [CmdletBinding()] [OutputType([string])] param ( [Parameter( Position = 0, Mandatory, ValueFromPipeline )] [ValidateNotNullOrEmpty()] [string]$String, [Parameter( Position = 1, Mandatory = $false )] [ValidateSet( 'Utf8', 'Utf16')] [string]$Encoding = 'Utf8' ) begin { $chars = [List[char]]::new() } process { $runes = @($String.EnumerateRunes()) for ($i = ($runes.Count - 1); $i -ge 0; $i--) { $rune = $runes[$i] switch ($Encoding) { 'Utf8' { $points = [char[]]::new($rune.Utf8SequenceLength) $rune.EncodeToUtf8($points) | Out-Null } 'Utf16' { $points = [char[]]::new($rune.Utf16SequenceLength) $rune.EncodeToUtf16($points) | Out-Null } Default { throw "'$Encoding' is not a valid encoding option." } } $chars.AddRange($points) } } end { return [string]::new($chars) } } |