Friday Fun - ความท้าทายเรื่องไร้สาระของ PowerShell
วันนี้ฉันคิดว่าฉันจะแบ่งปันโซลูชัน PowerShell ของฉันกับความท้าทาย Iron Scripter ล่าสุด ความท้าทายคือการสร้างโค้ด PowerShell ที่จะสร้างเอกสารไร้สาระ โดยมีเป้าหมายเพื่อสร้างไฟล์ตัวอย่าง 10 ไฟล์ที่เต็มไปด้วยคำพูดที่ไม่มีความหมาย ใช่ นอกจากอาจต้องการให้ไฟล์ทดสอบใช้งานได้แล้ว ความท้าทายก็ดูไม่มีจุดหมายเลย อย่างไรก็ตาม เช่นเดียวกับความท้าทายเหล่านี้ หรือแม้แต่ใน The PowerShell Practice Primer การเดินทางคือรางวัล คุณค่าที่แท้จริงคือการเรียนรู้วิธีใช้ PowerShell และอาจค้นพบเทคนิคหรือคำสั่งใหม่ๆ ความหวังก็คือระหว่างการทำงานกับความท้าทาย คุณจะพัฒนาทักษะการเขียนสคริปต์ PowerShell ของคุณ และใครจะรู้บางทีอาจมีความสนุกสนานเล็กน้อยไปพร้อมกัน
เอกสารไร้สาระ
ฉันได้ใส่ทุกอย่างไว้ในโมดูลบน Github ชื่อ PSNonsense
ฉันเข้าหาสิ่งนี้ด้วยแนวทางแบบเอกสารสำเร็จรูป ฉันเริ่มต้นด้วยฟังก์ชันเพื่อสร้างคำไร้สาระ นี่เป็นเรื่องง่ายพอ สิ่งที่ฉันต้องทำคือเลือกตัวละครแบบสุ่มจำนวนหนึ่งจากกลุ่มและรวมเข้าด้วยกัน
$letters = [Char[]]'abcdefghijklmnopqrstuvwxyz'
#add some diacritical characters
$letters += [Char]0x00EB,[Char]0x00E4,[Char]0x00E9
-join ( $letters | Get-Random -count $Length)
ฟังก์ชันเช่นเดียวกับฟังก์ชันทั้งหมด มีพารามิเตอร์เพื่อกำหนดความยาวหรือการนับ โดยใช้ค่าเริ่มต้นแบบสุ่ม ฉันยังใช้แอตทริบิวต์ ValidateSet เพื่อตรวจสอบค่าพารามิเตอร์ที่ผู้ใช้อาจป้อน
Param(
[Parameter(Position = 0, HelpMessage = "Indicate the word length between 1 and 10.")]
[ValidateRange(1, 10)]
[int]$Length = (Get-Random -Minimum 1 -Maximum 10)
)การสร้างคำไร้สาระเป็นเรื่องง่าย
PS C:\> New-NonsenseWord -Length 7
ëfswäna
ประโยคไร้สาระเป็นเพียงชุดของคำไร้สาระ แต่มีความท้าทายเพิ่มเติมในการแทรกเครื่องหมายวรรคตอนและเพื่อให้แน่ใจว่าประโยคจะลงท้ายด้วยจุด ฉันเพิ่มโค้ดเพื่อสุ่มจบบางประโยคด้วยเครื่องหมายคำถามหรือเครื่องหมายอัศเจรีย์
$punct = ", ", "; ", " - ", ": "
#define a flag to indicate if random punctuation has been inserted.
$NoPunct = $true
1..($WordCount - 1) | ForEach-Object -Begin {
#make sure we start the sentence with a word
[string]$sentence = New-NonsenseWord
} -process {
#insert random punctuation into the sentence, but only once
if (($WordCount -ge 10) -AND (Test) -AND $NoPunct) {
$sentence += $punct | Get-Random -Count 1
$NoPunct = $False
}
$sentence += "{0} " -f (New-NonsenseWord)
}
#capitalize the first word of the sentence.
#does the sentence end in a period, exclamation or question mark.
#The period should be the default most of the time
$rn = Get-Random -Maximum 100 -Minimum 1
Switch ($rn) {
{$_ -ge 90} {$end = "?" ; break}
{$_ -ge 82} { $end = "!"}
Default { $end = "."}
}
$out = "{0}{1}{2}" -f ([string]$sentence[0]).ToUpper(), $sentence.substring(1).TrimEnd(),$end
ฟังก์ชันนี้มีฟังก์ชันส่วนตัวที่เรียกว่า Test ซึ่งจะสุ่มกำหนดว่าฉันควรทำบางอย่างหรือไม่ เช่น การแทรกเครื่องหมายวรรคตอน
PS C:\> New-NonsenseSentence -WordCount 11
Urip; élthe qkvipwen kym h fäuq cwuoéhjnä ikafysqol eom ikäb yke.การสร้างย่อหน้าหมายถึงการรวมประโยคตามจำนวนที่กำหนดเข้าด้วยกัน
$raw = 1..$SentenceCount | Foreach-object {New-NonsenseSentence}
($raw -join " ").trimend()
เนื่องจากตัวอย่างจะใช้เวลานานขึ้นเล็กน้อย นี่คือภาพหน้าจอ
สังเกตเครื่องหมายวรรคตอน
การสร้างเอกสารไม่มีอะไรมากไปกว่าการรวบรวมย่อหน้า
#insert a return after each paragraph
1..$ParagraphCount | ForEach-Object {New-NonsenseParagraph;"`r"}
ด้วยฟังก์ชันนี้ New-NonsenseDocument ฉันสามารถใช้โค้ดแบบนี้เพื่อสร้างเอกสารได้ 10 ฉบับ
1..10 | ForEach-Object {
$filename = [System.IO.Path]::GetRandomFileName()
#replace the extension
$filename = $filename -replace "\.\w+", ".txt"
#build the path
$path = Join-Path -path $env:TEMP -ChildPath $filename
#create the document
#encode as UTF8 to save the diacritical characters
New-NonsenseDocument -ParagraphCount (Get-Random -Minimum 3 -Maximum 10) |
Out-File -FilePath $path -Encoding utf8
#view the result
Get-Item $path
}ฉันใช้ .NET Framework เพื่อสร้างชื่อไฟล์ Randome จากนั้นใช้รูปแบบ regex เพื่อแทนที่ส่วนขยายด้วยนามสกุล .txt เส้นทางไฟล์สุดท้ายถูกสร้างขึ้นโดยใช้ Join-Path ซึ่งแนะนำแทนที่จะพยายามต่อสตริงเข้าด้วยกัน คุณสามารถดูไฟล์ได้ในโฟลเดอร์ตัวอย่างในพื้นที่เก็บข้อมูล PSNonsense
มาร์กดาวน์เรื่องไร้สาระ
ความท้าทายนี้มีข้อกำหนดด้านเครดิตเพิ่มเติมเพื่อสร้างเอกสารลดราคาที่ไร้สาระ เอกสารมาร์กดาวน์มีข้อกำหนดเฉพาะสำหรับส่วนหัว ท้ายที่สุด ฉันสร้างไฟล์โดยใช้สตริงที่นี่ และแทรกองค์ประกอบมาร์กดาวน์ที่สร้างขึ้นแบบสุ่ม
เพื่อให้สิ่งต่าง ๆ ง่ายขึ้น (โดยสุจริต) ฉันรวมคำสั่ง PSNonsense ไว้ในฟังก์ชันตัวช่วยหรือตัวโกงสองสามตัว
function New-Heading {
(New-NonsenseSentence -WordCount (Get-Random -Minimum 1 -Maximum 5)) -replace "[.!?]", ""
}
function New-CodeFence {
$cmd = "$((New-NonsenseSentence -WordCount (Get-Random -Minimum 2 -Maximum 6)) -replace "[.!?]",'')"
#the backtick needs to be escaped so that end result is a proper markdown code fence.
#there should be 6 backticks.
$cf = @"
$('`'*6)powershell
PS C:\> $cmd
$('`'*6)
"@
$cf
}
function New-SubHead {
Param(
[int]$Level = 2
)
$h = "#"*$level
$head = "{0} {1}" -f $h, (New-Heading)
#write-host $head -ForegroundColor red
$out = @"
$head
"@
1..(Get-Random -Maximum 4) | ForEach-Object {
$p = (New-NonsenseParagraph -SentenceCount (Get-Random -Minimum 4 -Maximum 10) -outvariable pv)
if ((Get-Random)%3) {
#randomly format a string
$wds = ($p.split()).where( {$_ -match "\w+"})
$hl = $wds | Select-Object -skip (Get-Random -Minimum 7 -Maximum ($wds.count - 20)) -First (Get-Random -Minimum 1 -Maximum 7)
#randomly decide how to format
Switch ((Get-Random)) {
{$_%3} {$f = "*$($hl -join " ")*" }
{$_%5} {$f = "__$($hl -join " ")__"}
{$_%7} {$f = "__*$($hl -join " ")*__" }
{$_%4} {$f = "``$($hl -join " ")``" }
{$_%2} {$f = "[$($hl -join " ")](https://www.$(New-NonsenseWord).com)"}
}
#left justify to send to the here string to avoid extra spaces
$out += ($p -replace ($hl -join " "), $f)
} #if %3
else {
$out += $p
}
$out += "`n`n"
<#
the out variable is itself an array. I want to get the first item in that array,
which will be a string and then the first character in that string.
#>
if ($pv[0][0] -match "[aeifuylm]") {
#$out+="`n"
#increment if the next level is 4 or less
if ($level + 1 -le 4) {
$out += New-SubHead -level ($level + 1)
}
else {
#repeat the level
$out += New-SubHead -level $level
}
}
elseif ($pv[0][0] -match "[pjqrst]" ) {
$out += New-CodeFence
$out += "`n`n"
#add a bit more verbiage
$out += New-NonsenseParagraph -SentenceCount (Get-Random -Minimum 1 -Maximum 4)
}
} #foreach object
$out
} #New-SubHeadฉันให้ความท้าทายกับตัวเองมากขึ้นด้วยการสุ่มแทรกส่วนรั้วโค้ด และจัดรูปแบบวลีแบบสุ่ม ฉันคิดว่าความคิดเห็นในฟังก์ชั่นอธิบายกระบวนการคิดของฉัน ด้วยฟังก์ชันเหล่านี้และโมดูล PSNonsense ของฉัน ฉันสามารถเรียกใช้โค้ดเช่นนี้เพื่อสร้างเอกสาร markdown ที่ไร้สาระได้
$md = @"
# $(New-Heading)
$((New-SubHead).trimend())
__My additional New-Headings follow.__
"@
1..(Get-Random -maximum 5) | ForEach-Object {
$md += New-SubHead
}
$md += "Updated *$(Get-Date)*."
$md
#encode as UTF8 to save the diacritical characters
$md | Out-File -FilePath c:\work\nonsense.md -Encoding utf8
สตริงที่นี่มีบรรทัดว่างที่จำเป็นเพื่อสร้างเอกสารมาร์กดาวน์ที่เหมาะสม สังเกตข้อความเกี่ยวกับการเข้ารหัสไฟล์ หากคุณใช้อักขระพิเศษและไม่ได้ระบุ UTF8 ไฟล์อาจมีอักขระ '?' อยู่ในตำแหน่ง สิ่งหนึ่งที่ฉันสังเกตเห็นใน VS Code ก็คือในโหมดแก้ไข เอกสารมาร์กดาวน์นั้นใช้ได้ แต่เมื่อฉันใช้โหมดดูตัวอย่าง มันตรวจไม่พบอักขระพิเศษ ฉันไม่รู้ว่ามันเป็นข้อบกพร่องหรือการตั้งค่าที่ฉันยังไม่พบ ไม่ว่าคุณจะพบมาร์กดาวน์ไร้สาระของฉันและเวอร์ชัน PDF ในโฟลเดอร์ตัวอย่างบน Github
ฉันหวังว่าคุณจะใช้เวลาดูโค้ดในพื้นที่เก็บข้อมูลของโมดูล ตามหลักการแล้ว คุณจะลองด้วยตัวเองเพื่อดูว่ามันทำงานอย่างไรและเพราะเหตุใด หากคุณเรียนรู้สิ่งใหม่ ฉันหวังว่าคุณจะแจ้งให้เราทราบ
ในระหว่างนี้ ให้ใช้ PowerShell ต่อไปทุกวัน และหากคุณยังไม่มี ลองดูความท้าทายด้านการเขียนสคริปต์อื่นๆ ได้ที่ https://ironscripter.us และลองแก้ไขด้วยตนเอง ไม่มีการจำกัดเวลาหรือวันหมดอายุ และคุณอาจแปลกใจกับสิ่งที่คุณเรียนรู้
