特定字符在字符串中彼此出现的次数

时间:2017-09-03 10:53:33

标签: string powershell

我一直在寻找一种方法来计算特定字符在字符串中彼此出现的次数。我找到的所有方法都只计算字符串“A”出现在字符串中的次数。

Example of string:
0xAAABBC0123456789AABBCCDD0123456789ABCDEF

每个字符串长度为43个字符,以“0x”开头。每个字符串仅包含随机顺序的以下字符:0-9和A-F,(总共16个不同的字符)。每个角色可以连续多次出现在一行中,例如:“AAA”或" 111"。

我感兴趣的是,在一个字符串中,每个16个字符中的每一个最多出现多少次,并通过我的所有字符串进行检查。

到目前为止,我只提出了这个Powershell脚本,它计算每行每个字符出现的次数:

Get-Content " C:\Temp\strings.txt" | ForEach-Object{
    New-Object PSObject -Property @{
        Strings = $_
        Row = $_.ReadCount
        9 = [regex]::matches($_,"9").count
        D = [regex]::matches($_,"D").count
        B = [regex]::matches($_,"B").count
        C = [regex]::matches($_,"C").count
        7 = [regex]::matches($_,"7").count
        3 = [regex]::matches($_,"3").count
        1 = [regex]::matches($_,"1").count
        8 = [regex]::matches($_,"8").count
        F = [regex]::matches($_,"F").count
        2 = [regex]::matches($_,"2").count
        4 = [regex]::matches($_,"4").count
        E = [regex]::matches($_,"E").count
        6 = [regex]::matches($_,"6").count
        5 = [regex]::matches($_,"5").count
        A = [regex]::matches($_,"A").count
        0 = [regex]::matches($_,"0").count
    }
} | Sort Count -Descending | Export-Csv -Path "C:\Temp\output.csv" –NoTypeInformation

我最好在Powershell中这样做,但如果还有另一种方法可以更容易地做到这一点,请告诉我。

5 个答案:

答案 0 :(得分:0)

一种方法是逐个字符地迭代源字符串,并跟踪字符被看到的次数。这可以通过哈希表轻松完成。像这样,

# Hashtable initialization. Add keys for 0-9A-F:
# Each char has initial count 0
$ht = @{}
"ABCDEF0123456789".ToCharArray() | % {
    $ht.Add($($_.ToString()), 0)
}

# Test data, the 0x prefix will contain one extra zero
$s = "0xAAABBC0123456789AABBCCDD0123456789ABCDEF"    

# Convert data to char array for iteration
# Increment value in hashtable by using the char as key
$s.ToCharArray() | % { $ht[$_.ToString()]+=1 }

# Check results
PS C:\> $ht

Name                           Value
----                           -----
B                              5
3                              2
5                              2
x                              1
9                              2
2                              2
8                              2
0                              3
1                              2
E                              1
7                              2
F                              1
6                              2
4                              2
D                              3
A                              6
C                              4

答案 1 :(得分:0)

构建一个HexPair,迭代位置的字符串位置(省略最后一个),并以HexPair为键在哈希表中增加一个值。

$String = '0xAAABBC0123456789AABBCCDD0123456789ABCDEF'
$Hash=@{}
for ($i=2;$i -le ($string.length-2);$i++){
    $Hash[$($String.Substring($i,2))]+=1
}
$Hash.GetEnumerator()|ForEach-Object{
   [PSCustomObject]@{HexPair = $_.Name
                     Count = $_.Value}
} |Sort Count -Descending

示例输出

HexPair Count
------- -----
BC          3
AB          3
AA          3
CD          2
BB          2
9A          2
89          2
78          2
67          2
56          2
45          2
34          2
23          2
12          2
01          2
EF          1
DE          1
DD          1
D0          1
CC          1
C0          1

替代产品:

$Hash.GetEnumerator()|ForEach-Object{
    [PSCustomObject]@{HexPair = $_.Name
                      Count = $_.Value}
 } |Sort HexPair|group Count |%{"Count {0} {1}" -f $_.Name,($_.Group.HexPair -Join(', '))}|Sort
Count 1 C0, CC, D0, DD, DE, EF
Count 2 01, 12, 23, 34, 45, 56, 67, 78, 89, 9A, BB, CD
Count 3 AA, AB, BC

答案 2 :(得分:0)

您可以使用lookbehind和backreference将字符串拆分为重复的组:

$s = '0xAAABBC0123456789AABBCCDD0123456789ABCDEF'
$repeats = $s.Remove(0, 2) -split '(?<=(.))(?!\1|$)'

现在我们可以根据每个字母的第一个字母对子字符串进行分组:

$groups = $repeats |Group-Object {$_[0]} -AsHashTable

最后抓住每个角色的最长序列:

'0123456789ABCDEF'.ToCharArray() |%{
    [pscustomobject]@{
        Character = "$_"
        MaxLength = "$($groups[$_] |Sort Length -Descending |Select -First 1)".Length
    }
}

你应该得到一个列表(例如你的):

Character MaxLength
--------- ---------
0                 1
1                 1
2                 1
3                 1
4                 1
5                 1
6                 1
7                 1
8                 1
9                 1
A                 3
B                 2
C                 2
D                 2
E                 1
F                 1

答案 3 :(得分:0)

结果以这种方式出现,即使它为每个字符串提供了15个额外的行,我也可以轻松地在Microsoft Excel中过滤掉不需要的内容。

#Removed all "0x" in textfile before running this script
$strings = Get-Content " C:\Temp\strings_without_0x.txt"
foreach($s in $strings) {
$repeats = $s.Remove(0, 2) -split '(?<=(.))(?!\1|$)'

$groups = $repeats |Group-Object {$_[0]} -AsHashTable

'0123456789ABCDEF'.ToCharArray() |%{
    [pscustomobject]@{
        String = "$s"
        Character = "$_"
        MaxLength = "$($groups[$_] |Sort Length -Descending |Select -First 1)".Length
    }

} | Sort Count -Descending | Export-Csv -Path "C:\Temp\output.csv" -NoTypeInformation -Append}

感谢您的所有好评!

答案 4 :(得分:0)

尝试一下。

$out=@()
$string="0xAAABBC0123456789AABBCCDD0123456789ABCDEF"
$out+="Character,Count"
$out+='0123456789ABCDEF'.ToCharArray()|%{"$_," + ($string.split("$_")|Where-object{$_ -eq ""}).count}
ConvertFrom-Csv $out |sort count -Descending 

这将产生以下内容:

 Character Count
 --------- -----
 A         3    
 B         2    
 0         1    
 C         1    
 D         1    
 F         1    
 1         0    
 2         0    
 3         0    
 4         0    
 5         0    
 6         0    
 7         0    
 8         0    
 9         0    
 E         0    

您可以将其放入这样的函数中:

function count_dups ($string){
   $out=@() # null array
   $out+="Character,Count" # header
   $out+='0123456789ABCDEF'.ToCharArray()|%{"$_," + ($string.split("$_")|Where-object{$_ -eq ""}).count}
   return ConvertFrom-Csv $out | sort count -Descending
} 

我在这里所做的最大部分就是这行。

'0123456789ABCDEF'.ToCharArray()|%{"$_," + (string.split("$_")|Where-object{$_ -eq ""}).count}

我将字符串拆分为从字符数组'0123456789ABCDEF'输入的字符上的数组。然后我要计算数组中的空元素。

我仅创建数组$ out,以便可以像您的示例一样格式化输出。