Skip to content

Instantly share code, notes, and snippets.

@DrBob5188
Created June 6, 2022 11:57
Show Gist options
  • Save DrBob5188/36d587b5c2f6e6238bc948af241bed0f to your computer and use it in GitHub Desktop.
Save DrBob5188/36d587b5c2f6e6238bc948af241bed0f to your computer and use it in GitHub Desktop.
function Get-StringLCP
{
<#
.SYNOPSIS
Get the longest common string prefix from an array of strings.
.DESCRIPTION
Get the longest common string prefix from an array of strings.
Note that empty strings and null values are allowed in the array.
Nulls will be automatically type cast by PowerShell as an empty string.
Use the IgnoreEmptyStrings switch to stop processing empty strings.
.PARAMETER InputStrings
The array of strings from which the longest common prefix is sought.
.PARAMETER IgnoreEmptyStrings
Excludes empty strings from the processing. Use this option when the input
data may have nulls or empty strings. If a null or empty string is present
the return value will always be [string]::Empty
.PARAMETER IgnoreCase
Performs case insensitive comparisons on the strings
.INPUTS
<None>
.OUTPUTS
[string]
.NOTES
Version: 1.0
Author: Robert Thomson
Creation Date: 2022-03-19
Purpose/Change: Initial rewrite of code at rosettacode.org, as an advanced
function with options for case insensitive comparison and empty string
filtering.
References:
1) Longest common prefix - Rosetta Code. Rosettacode.org. (2022).
Retrieved 19 March 2022, from
https://rosettacode.org/wiki/Longest_common_prefix#PowerShell.
.EXAMPLE
Get-StringLCP -InputStrings @('foo', 'foobar')
This example performs a case-sensitive comparison to return 'foo'.
.EXAMPLE
Get-StringLCP -InputStrings @('foo', 'FOOBAR') -IgnoreCase
This example performs a case-insensitive comparison to return 'foo'.
.EXAMPLE
Get-StringLCP -InputStrings @('foo', $null, 'foobar')
Get-StringLCP -InputStrings @('foo', '', 'foobar')
These examples are equivalent and perform a case-sensitive comparison to return ''.
.EXAMPLE
Get-StringLCP -InputStrings @('foo', $null, 'foobar') -IgnoreEmptyStrings
Get-StringLCP -InputStrings @('foo', '', 'foobar') -IgnoreEmptyStrings
These examples are equivalent and perform a case-sensitive comparison to return 'foo'.
#>
[CmdletBinding()]
param(
[parameter(Mandatory)]
[AllowEmptyCollection()]
[AllowEmptyString()]
[string[]]$InputStrings,
[parameter()]
[Switch]$IgnoreEmptyStrings,
[parameter()]
[Switch]$IgnoreCase
)
if ($IgnoreEmptyStrings.IsPresent) {
$arr = ($InputStrings | Where-Object {
![String]::IsNullOrEmpty($_)
} | Sort-Object -Property {$_.length} | Select-Object -unique) -as [String[]]
}
else {
$arr = ($InputStrings | Sort-Object -Property {$_.length} | Select-Object -unique) -as [String[]]
}
switch ($arr.count) {
# Array is null or empty
0 {[string]::Empty}
# Longest common prefix of a single string is the string
1 {$arr[0]}
# Process 2 or more strings.
default {
$Limit = $arr[0].length
$i = 0
$test = $true
# Configure the grouping property scriptblock for case insensitive if required
if ($IgnoreCase.IsPresent) {
$sb = {[char]::ToUpper($_[$i])}
}
else {
$sb = {$_[$i]}
}
while (($i -lt $Limit) -and $test) {
# Group by letter. If the letters are the same for all the strings there will be only one group
$test = ($arr | Group-Object -Property $sb ).Name.Count -eq 1
if ($test) {
$i++
}
}
$arr[0].substring(0,$i)
}
}
}
# Main script part (untested)
$files = Get-ChildItem -Path .\ -File
$filenames = $files.Name
$Start = $End = 0
while ($start -lt $filenames.count -and $end -lt $filenames.count) {
do {
$lcp = Get-StringLCP -IgnoreCase -InputStrings $filenames[$start..$end++]
} while (-not [string]::IsNullOrEmpty($lcp))
if (($end - $start) -gt 1) {
$lcp = Get-StringLCP -IgnoreCase -InputStrings $filenames[$start..($end - 1)]
New-Item -Path ".\$lcp" -ItemType Directory
Move-Item -path $filenames[$start..($end - 1)] -Destination ".\$lcp"
}
$start = $End
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment