I'm trying to replace the word of in a string, with a PowerShell script.
I have tried an if statement:
$string = "a tale of two cities "
$array = $string -split " "
if($array -match 'of') {
$array -replace 'bob'
}
The statement works at detecting of but I don't know how to replace it with a different word.
A single expression using the -replace operator is all you need:
> 'a tale of two cities' -replace '\bof\b', 'bob'
a tale bob two cities
If you want the resulting string split into words by whitespace:
$array = -split 'a tale of two cities' -replace '\bof\b', 'bob'
I find the method version a bit simpler:
"a tale of two cities ".Replace('of','bob')
Or even:
$string = "a tale of two cities "
$string.Replace('of','bob')
Related
Given values to extract from a string, where each value is surrounded by a starting character and ending character, what would be the most effective way to achieve this?
eg, to get an array containing values: a b c
$mystring = "=a; =b; =c;"
$CharArray = $mystring.Split("=").Split(";")
There are numerous combinations of -replace, -split, .Split(), and .Replace() that could be used for this task. Here are some examples:
# Since each element is separated by a space, you can replace extraneous characters first
# -split operator alone splits by a space character
# This can have issues if your values contain spaces too
($mystring -replace '=|;').Split(' ')
-split ($mystring -replace '=|;')
# Since splitting creates white space at times, `Trim()` handles that.
# Because you expect an array after splitting, -ne '' will only return non-empty elements
$mystring.Split("=").Split(";").Trim() -ne ''
# Creates a array of of System.Char elements. Take note of the type here as it may not be what you want.
($mystring -replace ' ?=|;').ToCharArray()
# Uses Split(String[], StringSplitOptions) method
($myString -replace ' ?=').Split(';',[StringSplitOptions]::RemoveEmptyEntries)
David, what you have looks good yet here is another way to do it. The -replace method handles the space (" ") and equal sign (=).
$mystring = "=a; =b; =c;"
$CharArray = $mystring -split ";" -replace " |=",""
My question is two fold I'm playing around with PS and trying new stuff, I wrote a small script that generates full names by exporting first names from a txt.file and last names from another txt.file and finally randomly combines the 2 to create a full name, this is the script:
$Firstnames = Get-Content -Path 'C:\Users\user\Desktop\Firstname.txt'
$Lastnames = Get-Content -Path 'C:\Users\user\Desktop\Lastnames.txt'
$feminine = $firstnames | ?{$_ -like "*;frau"} | %{$_.Split(';')[0]}
Write-Host "Random full name generator"
$numberofNames = 1..(Read-Host 'how many combination do you want to generate?')
$numberofNames | foreach {
$f = $feminine[ (Get-Random $feminine.count)]
$l = $Lastnames[ (Get-Random $Lastnames.count)]
$full = $f+" "+$l
Write-output $full
}
1- now $numberofNames is an array 'a range operator', I would like to know what bad consequences could use this method have? is this the best approach for the users input?
2- what is the key difference between using for example $a = 100 and $a = 1..100?
in case you need to know:
$firstnames looks something like this:
Linda;frau
Aline;frau
Lisa;frau
Katja;frau
Karen;frau
and $lastnames:
smith
anderson
müller
klein
Rex
thank you
1- now $numberofNames is an array 'a range operator', i would like to know what bad consequences could using this method have? is this the best approach for the users input?
It's valid. Even if the user adds e.g. a string as input Powershell will throw an error that it could not cast the input to an int:
1 .. "test" | % {Write-Host $_ }
Cannot convert value "test" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:1
+ 1 .. "test" | % {Write-Host $_ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Even a neg. int shouldn't be a problem since you're not using the array content for any indexing operations.
2- what is the key difference between using for example $a = 100 and $a = 1..100?
$a = 100 points to integer with the value 100.
$a = 1..100 is an array with 100 entries.
So I'm trying to count the words of my text file however when I do get-content the array reads them letter by letter and so it doesn't let me compare them word by word. I hope you guys can help me out!
Clear-Host
#Functions
function Get-Articles (){
foreach($Word in $poem){
if($Articles -contains $Word){
$Counter++
}
}
write-host "The number of Articles in your sentence: $counter"
}
#Variables
$Counter = 0
$poem = $line
$Articles = "a","an","the"
#Logic
$fileExists = Test-Path "text.txt"
if($fileExists) {
$poem = Get-Content "text.txt"
}
else
{
Write-Output "The file SamMcGee does not exist"
exit(0)
}
$poem.Split(" ")
Get-Articles
What your script does, edited down a bit:
$poem = $line # set poem to $null (because $line is undefined)
$Articles = "a","an","the" # $Articles is an array of strings, ok
# check file exists (I skipped, it's fine)
$poem = Get-Content "text.txt" # Load content into $poem,
# also an array of strings, ok
$poem.Split(" ") # Apply .Split(" ") to the array.
# Powershell does that once for each line.
# You don't save it with $xyz =
# so it outputs the words onto the
# pipeline.
# You see them, but they are thrown away.
Get-Articles # Call a function (with no parameters)
function Get-Articles (){
# Poem wasn't passed in as a parameter, so
foreach($Word in $poem){ # Pull poem out of the parent scope.
# Still the original array of lines. unchanged.
# $word will then be _a whole line_.
if($Articles -contains $Word){ # $articles will never contain a whole line
$Counter++
}
}
write-host "The number of Articles in your sentence: $counter" # 0 everytime
}
You probably wanted to do $poem = $poem.Split(" ") to make it an array of words instead of lines.
Or you could have passed $poem words into the function with
function Get-Articles ($poem) {
...
Get-Articles $poem.Split(" ")
And you could make use of the PowerShell pipeline with:
$Articles = "a","an","the"
$poemArticles = (Get-Content "text.txt").Split(" ") | Where {$_ -in $Articles}
$counter = $poemArticles | Measure | Select -Expand Count
write-host "The number of Articles in your sentence: $counter"
TessellatingHeckler's helpful answer explains the problem with your approach well.
Here's a radically simplified version of your command:
$counter = (-split (Get-Content -Raw text.txt) -match '^(a|an|the)$').count
write-host "The number of articles in your sentence: $counter"
The unary form of the -split operator is key here: it splits the input into words by any run of whitespace between words, resulting in an array of individual words.
-match then matches the resulting array of words against a regex that matches words a, an, or the: ^(a|an|the)$.
The result is the filtered subarray of the input array containing only the words of interest, and .count simply returns that subarray's count.
So I made my input from the read-host into an array an figured it would let me count the amount of times a word in the sentence $a is seen from the $Array. however Count++ doesn't give me a total
function Get-Sentence($a){
if($a -contains $array) {
$Count++
}
else {
return 0
}
}
Write-Host "There are $count words"
[array]$Array = #("a", "an", "the")
[array]$a = Read-Host "Enter a long sentence from a story book or novel: ").split(" ")
Preferred approach:
Easiest way to accurately count occurrences of multiple substrings is probably:
Construct regex pattern that matches on any one of the substrings
Use the -split operator to split the string
Count the resulting number of strings and substract 1:
# Define the substrings and a sentence to test against
$Substrings = "a","an","the"
$Sentence = "a long long sentence to test the -split approach, anticipating false positives"
# Construct the regex pattern
# The \b sequence ensures "word boundaries" on either side of a
# match so that "a" wont match the a in "man" for example
$Pattern = "\b(?:{0})\b" -f ($Substrings -join '|')
# Split the string, count result and subtract 1
$Count = ($Sentence -split $Pattern).Count - 1
Outputs:
C:\> $Count
2
As you can see it will have matched and split on "a" and "the", but not the "an" in "anticipating".
I'll leave converting this into a function an exercise to the reader
Note:
if you start feeding more than just simple ASCII strings as input, you may want to escape them before using them in the pattern:
$Pattern = "\b(?:{0})\b" -f (($Substrings |ForEach-Object {[regex]::Escape($_)}) -join '|')
Naive approach:
If you're uncomfortable with regular expressions, you can make the assumption that anything in between two spaces is "a word" (like in your original example), and then loop through the words in the sentence and check if the array contains the word in question (not the other way around):
$Substrings = "a","an","the"
$Sentence = (Read-Host "Enter a long sentence from a story book or novel: ").Split(" ")
$Counter = 0
foreach($Word in $Sentence){
if($Substrings -contains $Word){
$Counter++
}
}
As suggested by Jeroen Mostert, you could also utilize a HashTable. With this you could track occurrences of each word, instead of just a total count:
$Substrings = "a","an","the"
$Sentence = (Read-Host "Enter a long sentence from a story book or novel: ").Split(" ")
# Create hashtable from substrings
$Dictionary = #{}
$Substrings |ForEach-Object { $Dictionary[$_] = 0 }
foreach($Word in $Sentence){
if($Dictionary.ContainsKey($Word)){
$Dictionary[$Word]++
}
}
$Dictionary
$Substrings = "a","an","the"
("a long long sentence to test the -split approach, anticipating false positives" -split " " | where {$Substrings -contains $_}).Count
I am exploring options for presenting multidimensional array in some specified format. Desired output is a single line string with elements within each dimension separated by specified character. For example:
$foo = #(#("A","B","C"),#("1","2","3"))
$bar = #()
foreach ($i in $foo)
{
$bar += $i -Join ", "
}
$bar -join "; "
Produces desired output. When number of dimensions in the array grows, or is variable within the nested elements, this approach becomes cumbersome.
I am wondering if exists some Powershell magic to assist with this task. Ideally, something like:
$foo[([] -join ", ")] -join "; "
And perhaps a solution that will scale well for more complex array configurations.
Thoughts?
this way?
$foo = #(#("A","B","C"),#("1","2","3"))
($foo | % { $_ -join ',' }) -join '; '