当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 应对 PowerShell Word to Phone 挑战

作者:精品下载站 日期:2024-12-14 07:59:15 浏览:16 分类:玩电脑

应对 PowerShell Word to Phone 挑战


几周前,Iron Scripter 面临的挑战是编写代码,使用电话上的字母表将短字符串转换为其数值。在原始帖子的评论中已经分享了许多解决方案。当然有很多方法可以应对挑战。这是我的成果。

将文本转换为数字

我从一个简单的哈希表开始。

$phone = @{
    2 = 'abc'
    3 = 'def'
    4 = 'ghi'
    5 = 'jkl'
    6 = 'mno'
    7 = 'pqrs'
    8 = 'tuv'
    9 = 'wxyz'
}

这些按键的名称很巧合,与我手机上的电话按键相对应。转换“help”意味着找到值及其键。

[玩转系统] 应对 PowerShell Word to Phone 挑战

Name 属性向我显示了密钥。我可以对其他字母重复此过程,连接键并得到结果:4357。这是我用来简化此操作并满足挑战的其他一些要求的函数。

Function Convert-TextToNumber {
[cmdletbinding()]
[Outputtype("int32")]

    Param(
        [Parameter(Position = 0, Mandatory, ValueFromPipeline)]
        [ValidatePattern("^[A-Za-z]{1,5}$")]
        [string]$Plaintext,
        [Parameter(HelpMessage = "A custom dictionary file which is updated everytime a word is converted")]   
        [string]$Dictionary = "mywords.txt"
    )

    Begin {
        Write-Verbose "[BEGIN  ] Starting: $($MyInvocation.Mycommand)"

        #define a simple hashtable
        $phone = @{
            2 = 'abc'
            3 = 'def'
            4 = 'ghi'
            5 = 'jkl'
            6 = 'mno'
            7 = 'pqrs'
            8 = 'tuv'
            9 = 'wxyz'
        }

        #initialize a dictionary list
        $dict = [System.Collections.Generic.List[string]]::new()
        if (Test-Path -path $Dictionary) {
            Write-Verbose "[BEGIN  ] Loading user dictionary from $Dictionary"            
            (Get-Content -path $Dictionary).foreach({$dict.add($_)})
            $originalCount = $dict.Count
            Write-Verbose "[BEGIN  ] Loaded $originalCount items"
        }
    } #begin
    Process {
        Write-Verbose "[PROCESS] Converting: $Plaintext"
        #add plaintext to dictionary if missing
        if ($dict -notcontains $Plaintext) {
            Write-Verbose "[PROCESS] Adding to user dictionary"
            $dict.Add($plaintext)
        }

        #this is a technically a one-line expression
        #get the matching key for each value and join together
        ($plaintext.ToCharArray()).ForEach({
         $val = $_ 
         ($phone.GetEnumerator().Where({$_.value -match $val}).name)}) -join ""
    } #process

    End {
        #commit dictionary to file if new words were added
        if ($dict.count -gt $originalCount) {
            Write-Verbose "[END    ] Ending: Saving updated dictionary $Dictionary"
            $dict | Out-File -FilePath $Dictionary -Encoding ascii -Force
        }
        Write-Verbose "[END    ] Ending: $($MyInvocation.Mycommand)"
    } #end
}
    

该函数接受长度不超过 5 个字符的单词的管道输入,并且只能是字母字符(大写或小写)。这就是我使用 ValidatePattern 正则表达式所做的事情。

我还提前计划并保留所有转换后的单词的文本文件。如果文件中不存在明文,则会添加它。如果字典列表中的项目数发生变化,我会更新 End 块中的文件。请注意,我使用的是通用列表对象而不是数组。

$dict = [System.Collections.Generic.List[string]]::new()

这种类型的对象的性能比数组好得多。此函数中的差异微不足道,但我更多地转向此模型而不是传统数组。

转换是在 Process 块中使用这一行表达式完成的。

($plaintext.ToCharArray()).ForEach({
         $val = $_ 
         ($phone.GetEnumerator().Where({$_.value -match $val}).name)}) -join ""

下面是该函数实际运行的体验。

[玩转系统] 应对 PowerShell Word to Phone 挑战

将数字转换为文本

转换回来只是稍微复杂一点。我可以使用相同的哈希表。这次,我需要获取与每个键关联的值。然后我可以构建一个正则表达式模式来搜索我的字典文件。让我首先向您展示详细输出来进行说明。

[玩转系统] 应对 PowerShell Word to Phone 挑战

这个word文件包含我转换的所有内容。这是使用更大的 Word 文件的相同效果。

[玩转系统] 应对 PowerShell Word to Phone 挑战

还记得我之前转换的那句话吗?

[玩转系统] 应对 PowerShell Word to Phone 挑战

这需要一些工作,但我可能能弄清楚。当然,更高质量的 Word 文件会有所帮助。这就是为什么我开始记录我转换的内容。

[玩转系统] 应对 PowerShell Word to Phone 挑战

Function Convert-NumberToText {
[cmdletbinding()]
    Param(
        [Parameter(Position = 0, Mandatory, ValueFromPipeline)]
        [ValidateRange(2, 99999)]
        [int]$NumericValue,
        [Parameter(Mandatory,HelpMessage= "Specify the path to the word dictionary file.")]
        [ValidateScript({Test-Path $_})]
        [string]$Dictionary
    )

    Begin {
        Write-Verbose "[BEGIN  ] Starting: $($MyInvocation.Mycommand)"

        $phone = @{
            2 = 'abc'
            3 = 'def'
            4 = 'ghi'
            5 = 'jkl'
            6 = 'mno'
            7 = 'pqrs'
            8 = 'tuv'
            9 = 'wxyz'
        }

        Write-Verbose "[BEGIN  ] Loading a word dictionary from $dictionary"
        $words = Get-Content -path $Dictionary

        Write-Verbose "[BEGIN  ] ...$($words.count) available words."

        #define a regex to divide the numeric value
        [regex]$rx = "\d{1}"

    } #begin
    Process {
        Write-Verbose "[PROCESS] Converting: $NumericValue"
        $Values = ($rx.Matches($NumericValue).value).ForEach({ $val = $_ ; ($phone.GetEnumerator() | Where-Object {$_.name -match $val}).value})

        Write-Verbose "[PROCESS] Converting: Possible values: $($Values -join ',')"
        #build a regex pattern with a word boundary
        $pattern = "\b"
        foreach ($value in $values ) {
            $pattern += "[$value]{1}"
        }
        $patternb += "\b"

        Write-Verbose "[PROCESS] Using pattern: $pattern"
        #output will be lower case
        [System.Text.RegularExpressions.Regex]::Matches($words, $pattern, "IgnoreCase") |
        Group-Object -Property Value |
        Select-Object -ExpandProperty Name |
        Sort-Object | 
        Foreach-Object {$_.tolower()}

    } #process

    End {
        Write-Verbose "[END    ] Ending: $($MyInvocation.Mycommand)"
    } #end
}
    

如果您想尝试我的更大的 Word 文件,请在此处下载。

了解更多

在这个挑战中有很多很棒的学习机会。如果您发现自己想要或需要了解更多信息,我鼓励您查看 Pluralsight.com 上的 PowerShell 内容。我什至有一门关于 PowerShell 和正则表达式的课程。要真正将您的脚本编写提升到一个新的水平,请获取《PowerShell 脚本编写和工具制作》一书的副本。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯