Strings, Arrays and Functions in PowerShell v2 (and some sample code that speaks for itself :-)
I spent some more time experimenting with PowerShell v2 and here goes my second post about it.
This time around I am focusing on how to define variables, use expressions and create functions.
The "problem" we're solving :-)
To make it fun, I decided to create a little script that creates some random syllables, words and sentences using a set of rules. This will come out as some nonsense sentences, but they should be pronounceable. I wrote this little program in several languages before and it generally exercises a number of concepts around manipulating arrays and strings. It uses random numbers and sets of consonants and vowels, plus some logic around the number of syllables per word, words per sentence, etc.
Here are a few sample sentences created by the program:
- Inepirula beicmicso phosa.
- Ci muesit sacoipae naepdave opeefane.
- Kikipor sofestrysu crasha browohocyn.
- De dyczershaco kurensataer mexi trerememee.
- Cie he cho cyuba lio goabryntune.
- Quiaphe breiepco henureme sopoche.
- Pychurmabie osipi leberoi.
- Ne trirorce auencuep je sucootoi yeelneer.
- Uchekepian rinsi reypbar.
- Oeciurgo vacra go.
It’s gibberish, I know, but you should be able to pronounce it. In fact, I went one step further and used the Speech API in Windows to actually have the computer say them out loud.
P.S.: Due to its random nature, it is possible (although somewhat unlikely) that the program might spit out some bad words in some real language. I apologize in advance :-)
What I learned
PowerShell proved quite capable of creating this program. In fact, due to its interesting abilities to turn strings into arrays, rich expressions and loop constructs, it was no problem at all.
I did learn a few details that always vary from language to language:
· PowerShell uses a $ sign before the name of variables
· When creating variables, you can specify the type in [], but that is optional
· Common types include int32, array, string and object
· Get-Random(n) will give you a random integer between 0 and (n-1).
· Strings are arrays of characters starting at item number 0
· The -split operator can turn a string into an array, splitting the string using a specified delimiter
· Substring is the function to get a piece of a string
· Length is the function to get the number of characters in a string (or items in an array)
· Some operators are a bit tricky and it doesn’t use the regular "<", ">", "<=", ">=", "!=" and "==" operators. You need to use "-lt", "-gt", "-le", "-ge", "-ne" and "-eq" instead (there are many more). You get used to it.
· You can use the “+=”, “-=”, “*=” assignment syntax as you have in C++, C#
· You will sometimes need to enclose an expression in ( ) so that it is not confused with a statement
· You can use the multiply operator to repeat a string. For instance (“-“ * 5) yields “-----“. This is one of those cases where you must use the ().
· You can create COM objects with the ‘New-Object -ComObject “name”’ syntax
· In loops and conditional statements, you use () to specify the conditions and { } to group the statements
· The default execution policy will not let you run an unsigned script. You can bypass this using “Set-ExecutionPolicy Unrestricted -scope process”. Note that this will only apply for the running process, due to the –scope parameter. You can set this at a wider scope, but you probably shouldn’t, for security reasons.
Closing comments
Last but not least, find the code below. I tested this on Windows Server 2008 R2. Try it only on a test machine.
You should probably save it in a file called sentences.ps1 (for instance) and run it from there using “.sentences.ps1”.
Consider using the Powershell ISE, which includes a debugger.
Use CTRL-C to stop it before it says all 10 sentences. You might have to wait for it to end saying a sentence before it actually stops.
The code
[array] $Vowels = "a;a;a;a;e;e;e;e;i;i;i;o;o;o;u;u;y" -split ";"
[array] $Consonants = "b;b;br;c;c;c;ch;cr;d;f;g;h;j;k;l;m;m;m;n;n;p;p;ph;qu;r;r;r;s;s;s;sh;t;tr;v;w;x;z" -split ";"
[array] $Endings = "r;r;s;r;l;n;n;n;c;c;t;p" -split ";"
[object] $Voice = New-Object -ComObject "SAPI.SPVoice"
function Get-RandomVowel
{ return $Vowels[(Get-Random($Vowels.Length))] }
function Get-RandomConsonant
{ return $Consonants[(Get-Random($Consonants.Length))] }
function Get-RandomEnding
{ return $Endings[(Get-Random($Endings.Length))] }
function Get-RandomSyllable ([int32] $PercentConsonants, [int32] $PercentEndings)
{
[string] $Syllable = ""
if ((Get-Random(100)) -le $PercentConsonants)
{ $Syllable+= Get-RandomConsonant }
$Syllable+= Get-RandomVowel
if ((Get-Random(100)) -le $PercentEndings)
{ $Syllable+= Get-RandomEnding }
return $Syllable
}
function Get-RandomWord ([int32] $MinSyllables, [int32] $MaxSyllables)
{
[string] $Word = ""
[int32] $Syllables = ($MinSyllables) + (Get-Random(($MaxSyllables - $MinSyllables + 1)))
for ([int32] $Count=1; $Count -le $Syllables; $Count++)
{ $Word += Get-RandomSyllable 70 20 } <# Consonant 70% of the time, Ending 20% #>
return $Word
}
function Get-RandomSentence ([int32] $MinWords, [int32] $MaxWords)
{
[string] $Sentence = ""
[int32] $Words = ($MinWords) + (Get-Random($MaxWords - $MinWords + 1))
for ([int32] $Count=1; $Count -le $Words; $Count++)
{
$Sentence += Get-RandomWord 1 5 <# Word with 1 to 5 syllables #>
$Sentence += " "
}
$Sentence = $Sentence.substring(0,1).ToUpper() + $Sentence.substring(1,$Sentence.Length-2) + "."
return $Sentence
}
for ([int32] $Count=1; $Count -le 10; $Count++)
{
[string] $Sentence = Get-RandomSentence 2 6 <# Sentence with 2 to 6 words #>
Write-Host $Sentence
Write-Host ("-" * $Sentence.Length)
[int32] $VResult = $Voice.Speak($Sentence)
}
Improve it
Now that you got this code, you might want to work on it and make it better. Maybe changing the frequency of the consonants, vowels and endings. Maybe tweak the number of syllables per word or words per sentence. You might even think of ways to make it generate some poetry with the right number of syllables per sentence and some rhyming. Have fun…