PowerShell中两个以上字符串的最长公共子字符串?

PowerShell中两个以上字符串的最长公共子字符串?,powershell,Powershell,如何在PowerShell中的字符串数组中找到匹配的字符串: 例如: $Arr = "1 string first", "2 string second", "3 string third", "4 string fourth" 使用此示例,我希望返回以下内容: " string " 我想用它来查找文件名的匹配部分,然后删除该部分文件名(例如,从一组mp3文件中删除艺术家的姓名),而不必指定手动替换文件名的哪一部分。如果我理解您的问题: $Arr = "1 string first", "2

如何在PowerShell中的字符串数组中找到匹配的字符串:

例如:

$Arr = "1 string first",
"2 string second",
"3 string third",
"4 string fourth"
使用此示例,我希望返回以下内容:

" string "

我想用它来查找文件名的匹配部分,然后删除该部分文件名(例如,从一组mp3文件中删除艺术家的姓名),而不必指定手动替换文件名的哪一部分。

如果我理解您的问题:

$Arr = "1 string first", "2 string second", "3 string third", "4 string fourth"
$Arr -match " string " | foreach {$_ -replace " string ", " "}
如果它(艺术家姓名等)只是一个单词:

$Arr = "1 string first", "2 string second", "3 string third", "4 string fourth"
$common = $Arr | %{ $_.split() } | group | sort -property count | select -last 1 | select -expand name
$common = " {0} " -f $common
更新:

似乎适用于多个单词的实现(查找单词的最长公共子字符串):

下面是PowerShell中两个字符串的“最长公共子字符串”函数(基于wikibooks):

若要将其用于两个以上的字符串,请如下使用:

Function get-LongestCommonSubstringArray
{
Param(
[Parameter(Position=0, Mandatory=$True)][Array]$Array
)
    $PreviousSubString = $Null
    $LongestCommonSubstring = $Null
    foreach($SubString in $Array)
    {
        if($LongestCommonSubstring)
        {
            $LongestCommonSubstring = get-LongestCommonSubstring $SubString $LongestCommonSubstring
            write-verbose "Consequtive diff: $LongestCommonSubstring"
        }else{
            if($PreviousSubString)
            {
                $LongestCommonSubstring = get-LongestCommonSubstring $SubString $PreviousSubString
                write-verbose "first one diff: $LongestCommonSubstring"
            }else{
                $PreviousSubString = $SubString
                write-verbose "No PreviousSubstring yet, setting it to: $PreviousSubString"
            }
        }
    }
    Return $LongestCommonSubstring
}


get-LongestCommonSubstringArray $Arr -verbose
  • 生成InputString的所有唯一子字符串的列表
  • 筛选出现次数为#InputString的子字符串(即在所有输入字符串中)
  • 根据子字符串的长度对这些已过滤的子字符串进行排序
  • 返回此列表的最后一个(即最长的)

OP询问如何找到“字符串”是常见的字符串。这是正确的。我试图找到“字符串”是最常见的。它可以是任何东西,一组单词,可能有下划线,等等@Winfred-如果你想要一组单词,它会变得更复杂…你必须花一些时间来获取代码…最坏的情况下,我可以尝试将每个字符串转换为一个字符数组,然后开始比较各个字符。但是多维度阵列伤了我的头。我希望有人已经有一段代码可以做到这一点。@Winfred-因为这是一个很常见的问题,所以我写了一些似乎有效的东西。更新答案。试用/扩展它。它可以处理单个单词或多个单词,但当字符串不包含空格时,它会崩溃:$arr=“Name\u Artist\u Lovely”,“Name\u Artist\u Song”,“Name\u Artist\u SoPretty”应返回:“Name\u Artist\u”但返回:“Name\u Artist\u SoPretty”听起来你在寻找最长的公共子字符串。一个快速搜索,我还没有在网上看到任何PowerShell算法的实现。谢谢你,伙计。。这让我找到了正确的方向。我发现了一个C#最长的CommonSubString,它只需要几分钟就可以转换为PowerShell。是时候更新问题了。应该能够运行多次,并结合结果。除非我睡眠不足,否则最长的公共子串应该是可传递的,所以像这样的东西应该可以工作:LCS(LCS(LCS(12)3)4)。我不认为LCS是可传递的。考虑这些字符串:“一些大字符串”,“其他一些大字符串”,“一些东西”。如果你做了LCS(3,LCS(1,2)),那么你会得到“ing”而不是“some”,你是对的。对于我的特殊问题,这不是一个问题,但我不会标记已回答的问题。我将在其他时间重新研究代码,并尝试找出一种更好的解决方法。这可以通过1)仅为最短字符串生成子字符串(
$shortest=$arr | sort Length | select-first 1
),以及2)按长度顺序生成子字符串:
$Length..1 | foreach{$l=$0..$Length-$l)| foreach{$shortest.Substring(${,$l)}}其中{@($arr-match[regex]::Escape($})).Count-eq$arr.Count}选择-first 1
Function get-LongestCommonSubstring
{
Param(
[string]$String1, 
[string]$String2
)
    if((!$String1) -or (!$String2)){Break}
    # .Net Two dimensional Array:
    $Num = New-Object 'object[,]' $String1.Length, $String2.Length
    [int]$maxlen = 0
    [int]$lastSubsBegin = 0
    $sequenceBuilder = New-Object -TypeName "System.Text.StringBuilder"

    for ([int]$i = 0; $i -lt $String1.Length; $i++)
    {
        for ([int]$j = 0; $j -lt $String2.Length; $j++)
        {
            if ($String1[$i] -ne $String2[$j])
            {
                    $Num[$i, $j] = 0
            }else{
                if (($i -eq 0) -or ($j -eq 0))
                {
                        $Num[$i, $j] = 1
                }else{
                        $Num[$i, $j] = 1 + $Num[($i - 1), ($j - 1)]
                }
                if ($Num[$i, $j] -gt $maxlen)
                {
                    $maxlen = $Num[$i, $j]
                    [int]$thisSubsBegin = $i - $Num[$i, $j] + 1
                    if($lastSubsBegin -eq $thisSubsBegin)
                    {#if the current LCS is the same as the last time this block ran
                            [void]$sequenceBuilder.Append($String1[$i]);
                    }else{ #this block resets the string builder if a different LCS is found
                        $lastSubsBegin = $thisSubsBegin
                        $sequenceBuilder.Length = 0 #clear it
                        [void]$sequenceBuilder.Append($String1.Substring($lastSubsBegin, (($i + 1) - $lastSubsBegin)))
                    }
                }
            }
        }
    }
    return $sequenceBuilder.ToString()
}
Function get-LongestCommonSubstringArray
{
Param(
[Parameter(Position=0, Mandatory=$True)][Array]$Array
)
    $PreviousSubString = $Null
    $LongestCommonSubstring = $Null
    foreach($SubString in $Array)
    {
        if($LongestCommonSubstring)
        {
            $LongestCommonSubstring = get-LongestCommonSubstring $SubString $LongestCommonSubstring
            write-verbose "Consequtive diff: $LongestCommonSubstring"
        }else{
            if($PreviousSubString)
            {
                $LongestCommonSubstring = get-LongestCommonSubstring $SubString $PreviousSubString
                write-verbose "first one diff: $LongestCommonSubstring"
            }else{
                $PreviousSubString = $SubString
                write-verbose "No PreviousSubstring yet, setting it to: $PreviousSubString"
            }
        }
    }
    Return $LongestCommonSubstring
}


get-LongestCommonSubstringArray $Arr -verbose
$arr =  "qdfbsqds", "fbsqdt", "bsqda" 
$arr | %{

$substr = for ($s = 0; $s -lt $_.length; $s++) {
           for ($l = 1; $l -le ($_.length - $s); $l++) {
            $_.substring($s, $l);
           }
          } 
$substr | %{$_.toLower()} | select -unique

} | group | ?{$_.count -eq $arr.length} | sort {$_.name.length} | select -expand name -l 1
# returns bsqd