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
Related
I have an integer array like below and I wanted to count number of 1's in that array in powershell, Can anyone help me here please,
[array]$inputs = 81,11,101,1811,1981
$count = 0
foreach($input in $inputs)
{
Write-Host "Processing element $input"
$count += ($input -like "*1*" | Measure-Object).Count
}
Write-Host "Number of 1's in the given array is $count"
It gives me only 5 1's in that array but expected answer is 10. Any help would be appreciated
Starting with a side note:
Don't use $Input as a custom variable as it is a preserved automatic variable
For what you are trying:
You iterating trough an array and check whether each item (with will automatically type cast to a string) is -like a 1 preceded by any number of characters and succeeded by any number of characters which is either true or false (and not the total number of ones in the string).
Instead
You might want to use the Select-String cmdlet with the -AllMatches switch which counts all the matches:
[array]$inputs = 81,11,101,1811,1981
$count = 0
foreach($i in $inputs)
{
Write-Host "Processing element $input"
$count += ($i | Select-String 1 -AllMatches).Matches.Count
}
Write-Host "Number of 1's in the given array is $count"
In fact, thanks to the PowerShell member enumeration feature, you do not even have to iterate through each array item for this, and just simplify it to this:
[array]$inputs = 81,11,101,1811,1981
$count = ($Inputs | Select-String 1 -AllMatches).Matches.Count
Write-Host "Number of 1's in the given array is $count"
Number of 1's in the given array is 10
I solved the above issue with below script,
[string]$inputs = 81,11,101,1811,1981
$count = 0
foreach($i in $inputs.ToCharArray())
{
if($i -eq "1")
{$count++}
}
Write-Host "Number of 1's in the given array is $count"
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 " |=",""
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')
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.
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 '; '