PoshBytes: 12 Logical Days of Christmas

PoshBytes: 12 Logical Days of Christmas

Use PowerShell loops and Unicode-safe logic to generate the 12 Days of Christmas with while learning why CharArray breaks certain elements and how StringInfo fixes it.

This post is a companion for the video embedded below. Scroll down to see the code from the video.

Logical 12 Days of Christmas (No Emojis Yet)

Set ordinal names for days

$days = "First","Second","Third","Fourth","Fifth","Sixth",
        "Seventh","Eighth","Ninth","Tenth","Eleventh","Twelfth"

Define our gifts

$gifts = @(
    "a Partridge in a Pear Tree",
    "two Turtle Doves",
    "three French Hens",
    "four Calling Birds",
    "five Gold Rings",
    "six Geese a-Laying",
    "seven Swans a-Swimming",
    "eight Maids a-Milking",
    "nine Ladies Dancing",
    "ten Lords a-Leaping",
    "eleven Pipers Piping",
    "twelve Drummers Drumming"
)

loop through each 12 days

for ($i = 0; $i -lt 12; $i++) {
    Write-Host "`nOn the $($days[$i]) day of Christmas, my true love sent to me:"

    # Count down from the current day to display the gifts
    for ($j = $i; $j -ge 0; $j--) {

        Write-Host " - " -NoNewline
        # Add "and" before the last gift if it's not the first day
        if ($i -gt 0 -and $j -eq 0) {
            Write-Host "and " -NoNewline
        }
        # Split string into characters and loop through each for typing effect
        $gifts[$j].ToCharArray() | ForEach-Object {
            Write-Host -NoNewline $_
            Start-Sleep -Milliseconds 100
        }
        Write-Host ''
    }
    Start-Sleep -Milliseconds 500
}

Handling Emojis Without Breaking Them

Replace gifts with emojis

$gifts = @(
    "a 🐦 in a 🍐 🌳 ",
    "two 🐒 πŸ•ŠοΈπŸ•ŠοΈ",
    "three πŸ‡«πŸ‡· πŸ”",
    "four πŸ“£ 🐦",
    "five πŸͺ™ πŸ’",
    "six πŸ¦† a-πŸ₯š",
    "seven 🦒 a-🏊",
    "eight 🧹 a-πŸ„",
    "πŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒπŸ’ƒ",
    "ten 🀴 a-🦘",
    "eleven πŸ§‘β€πŸŽ€ πŸͺˆ",
    "twelve πŸ›’οΈ πŸ₯"
)

Why `.ToCharArray()` Fails With Emojis

Example of .ToCharArray() splitting characters

"Téd".ToCharArray()

        # CharArray doesn't handle emojis well, so use StringInfo
        $chars = [System.Globalization.StringInfo]::GetTextElementEnumerator($gifts[$j])
        while ($chars.MoveNext()) {
            Write-Host -NoNewline $chars.GetTextElement()
            Start-Sleep -Milliseconds 100
        }

Wrap Up

β€’ $i represents the current day
β€’ We print the intro line for that day
β€’ $j starts at the current day
β€’ It decreases to zero
β€’ This recreates the β€œstacking” effect of the song
β€’ Loops and arrays to build the 12 Days of Christmas
β€’ Nested loops to accumulate previous days’ gifts
β€’ Adding emojis to make the output festive and readable
β€’ Why .ToCharArray() breaks emojis due to UTF-16 surrogate pairs
β€’ Using System.Globalization.StringInfo to iterate emoji-safe text elements