Private/ConvertTo-DepartmentalGroupName.ps1
|
<# .SYNOPSIS Builds a departmental group name. .DESCRIPTION Private helper behind Get-DepartmentalGroupName and New-TcsEntraDepartmentalGroup. See the help of Get-DepartmentalGroupName for the naming rules. Returns nothing when the division has no usable words after clean-up. .PARAMETER Prefix The first part of the name. .PARAMETER Division The division. .PARAMETER Department The optional department. .PARAMETER Suffix The optional last part of the name. #> function ConvertTo-DepartmentalGroupName { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] $Prefix, [Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $Division, [string] $Department, [string] $Suffix ) $stopWords = New-Object -TypeName 'System.Collections.Generic.HashSet[string]' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase) foreach ($stopWord in @('and', 'of', 'the', '&')) { $null = $stopWords.Add($stopWord) } # Splits text into segments (arrays of words). A hyphen on its own ('HR - Payroll') or at the start # or end of a word separates segments; a hyphen inside a word ('7-zip') is kept. $getSegments = { param([string]$Text) $clean = $Text -replace '&', ' and ' # Apostrophes (straight, typographic U+2019 and backtick) are removed so "Children's" stays one word $clean = $clean -replace ('[''`{0}]' -f [char]0x2019), '' $clean = $clean -replace '[^\p{L}\p{M}\p{Nd}\s-]', ' ' $segments = New-Object -TypeName 'System.Collections.Generic.List[object]' $current = New-Object -TypeName 'System.Collections.Generic.List[string]' foreach ($token in @($clean -split '\s+' | Where-Object { $_ })) { $word = ($token -replace '-{2,}', '-').Trim('-') if ($token.StartsWith('-', [System.StringComparison]::Ordinal) -and $current.Count -gt 0) { $segments.Add($current.ToArray()) $current.Clear() } if ($word) { $current.Add($word) } if ($token.EndsWith('-', [System.StringComparison]::Ordinal) -and $current.Count -gt 0) { $segments.Add($current.ToArray()) $current.Clear() } } if ($current.Count -gt 0) { $segments.Add($current.ToArray()) } , $segments.ToArray() } $divisionSegments = & $getSegments $Division $divisionWords = @($divisionSegments | ForEach-Object { $_ }) $meaningfulWords = @($divisionWords | Where-Object { -not $stopWords.Contains($_) }) if ($meaningfulWords.Count -eq 0) { # The callers write the error; nothing is thrown so -ErrorVariable only records their error return } $parts = New-Object -TypeName 'System.Collections.Generic.List[string]' $parts.Add($Prefix) $departmentSegments = @() if (-not [string]::IsNullOrWhiteSpace($Department)) { $departmentSegments = & $getSegments $Department } if ($departmentSegments.Count -gt 0) { # Initials of the division: short all-caps words (acronyms such as IT or HR, 2 to 4 characters) # are kept whole, stop words are skipped $initials = -join @(foreach ($word in $meaningfulWords) { if ($word.Length -ge 2 -and $word.Length -le 4 -and $word -cmatch '^[\p{Lu}\p{Nd}]+$' -and $word -cmatch '\p{Lu}') { $word } else { $word.Substring(0, 1).ToUpperInvariant() } }) $divisionName = ConvertTo-TcsPascalCaseName -Text ($divisionWords -join ' ') $parts.Add($initials) # Drop leading department segments that repeat the division ('HR - Payroll' in Human Resources) $index = 0 while ($index -lt $departmentSegments.Count) { $segmentName = ConvertTo-TcsPascalCaseName -Text ($departmentSegments[$index] -join ' ') if ([string]::Equals($segmentName, $initials, [System.StringComparison]::OrdinalIgnoreCase) -or [string]::Equals($segmentName, $divisionName, [System.StringComparison]::OrdinalIgnoreCase)) { $index++ } else { break } } for (; $index -lt $departmentSegments.Count; $index++) { $parts.Add((ConvertTo-TcsPascalCaseName -Text ($departmentSegments[$index] -join ' '))) } } else { foreach ($segment in $divisionSegments) { $parts.Add((ConvertTo-TcsPascalCaseName -Text ($segment -join ' '))) } } if ($Suffix) { $parts.Add($Suffix) } # Remove empty parts and a part that repeats the one before it ('SG-HR-HR') $result = New-Object -TypeName 'System.Collections.Generic.List[string]' foreach ($part in $parts) { if (-not $part) { continue } if ($result.Count -gt 0 -and [string]::Equals($result[$result.Count - 1], $part, [System.StringComparison]::OrdinalIgnoreCase)) { continue } $result.Add($part) } $result -join '-' } |