How to get tv show episode and session number from title - powershell

I'm try to get tvhsow season and episode number from the title
I try following code which works but it also picking up title like xxxxe 3 as episode 3
$episode = $title | Select-String -Pattern "E(\d+)", "E (\d+)", "Episode (\d+)" | % {$_.Matches.Groups[1].Value}
$season = $title | Select-String -Pattern "S(\d+)", "S (\d+)", "Season (\d+)" | % {$_.Matches.Groups[1].Value}
How to i make sure that I can pick up the season number and episode from any of these formats.
xxx S01E01
xxxe 1 S01E01
xxx S01 E01
xxx 01x01
xxx Season 01 Episode 01
If above seaon or episode numbers are not in the title of the show then I just want to return nothing e.g. if the show is named as "xxxxxE 1"

Assuming the following
Seasons and episodes will always be 2 (or more) numbers
Seasons and episodes will always be at the end of the filename.
I would recommend anchoring to the end of the name with the regex pattern. From there we account for 0 or more characters before a period (file extension), 1 literal period (for the extension), 0 or more characters between the period and the episode, and 0 or more characters between the season and the episode.
$examples = #'
xxx S01E02.avi
xxxe 1 S02E03.mp3
xxx S03 E04.mov
xxx 04x05.png
xxx Season 05 Episode 06.wav
'# -split [environment]::NewLine
$examples | ForEach-Object {
if($_ -match '.+(\d{2,}).*(\d{2,}).*\..*$'){
"Season: {0} Episode: {1}" -f $matches.1,$matches.2
}
}
This will output
Season: 01 Episode: 02
Season: 02 Episode: 03
Season: 03 Episode: 04
Season: 04 Episode: 05
Season: 05 Episode: 06
You didn't show how you populated $title, so it was assumed to just be a string. However if you wanted to apply to file objects, you have a couple of options.
We can leave the regex pattern alone and use the Name property.
$videolist = Get-Childitem -Path path\to\movies -Filter *.whatever
foreach($video in $videolist){
if($video.Name -match '.+(\d{2,}).*(\d{2,}).*\..*$'){
"Season: {0} Episode: {1}" -f $matches.1,$matches.2
}
}
or
We can use the BaseName property and adjust the regex slightly.
$videolist = Get-Childitem -Path path\to\movies -Filter *.whatever
foreach($video in $videolist){
if($video.BaseName -match '.+(\d{2,}).*(\d{2,}).*$'){
"Season: {0} Episode: {1}" -f $matches.1,$matches.2
}
}

You could construct a regex string that parses out the season and episode numbers like this:
$examples = 'xxx S01E01','xxxe 1 S01E03','xxx S06 E01','xxx 01x01','xxx Season 01 Episode 02'
foreach ($title in $examples) {
if ($title -match '(?:(?:S(?:eason)?)?\s*(\d+)[\sx]*)(?:(?:E(?:pisode)?)?\s*(\d+))') {
$season = [int]$matches[1]
$episode = [int]$matches[2]
# just to display the output:
[PsCustomObject]#{
Title = $title
Season = $season
Episode = $episode
}
}
}
Output:
Title Season Episode
----- ------ -------
xxx S01E01 1 1
xxxe 1 S01E03 1 3
xxx S06 E01 6 1
xxx 01x01 1 1
xxx Season 01 Episode 02 1 2
Regex details:
(?: # Match the regular expression below
(?: # Match the regular expression below
S # Match the character “S” literally
(?: # Match the regular expression below
eason # Match the characters “eason” literally
)? # Between zero and one times, as many times as possible, giving back as needed (greedy)
)? # Between zero and one times, as many times as possible, giving back as needed (greedy)
\s # Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
* # Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
( # Match the regular expression below and capture its match into backreference number 1
\d # Match a single digit 0..9
+ # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
[\sx] # Match a single character present in the list below
# A whitespace character (spaces, tabs, line breaks, etc.)
# The character “x”
? # Between zero and one times, as many times as possible, giving back as needed (greedy)
)
(?: # Match the regular expression below
(?: # Match the regular expression below
E # Match the character “E” literally
(?: # Match the regular expression below
pisode # Match the characters “pisode” literally
)? # Between zero and one times, as many times as possible, giving back as needed (greedy)
)? # Between zero and one times, as many times as possible, giving back as needed (greedy)
\s # Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
* # Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
( # Match the regular expression below and capture its match into backreference number 2
\d # Match a single digit 0..9
+ # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
)
I have changed some of your examples to make it clearer the numbers are correctly found

Related

How to find a specific number of digits in string

I don't understand the Regex :(
I want to find if a path contains only 7 digits
For an example:
C:\Users\3D Objects\1403036 --> the result should be 1403036
C:\Users\358712\1403036 --> the result should be 1403036
and so on
I have tried:
$FilesPath -match '([\d{1,7}]{7})')
and
$FilesPath -match '(\d{7})')
Currently I am working with that:
$FilesPath = Read-Host -Prompt
if ($Matches[1].Length -eq '7') {
$FolderNumber = $Matches[1]
}
This is not right because there is no match if the path contains the number 3 in the path
If this is the case:
C:\Users\3D Objects\1403036854 --> More than 7 digits the result should be empty
or
C:\Users\3874113353D Objects\1403036 --> Should return result for 1403036
I don't have an array, just want to get if there is a number with exactly 7 digits and don't if contains less or more than 7 digits
You mean something like this?
# as example the paths as aray to loop over
'C:\Users\3D Objects\1403036', 'C:\Users\358712\1403036',
'C:\Users\somewhere\1234567', 'C:\Users\3D Objects\1403036854' | ForEach-Object {
# return the number anchored at the end of the string with exactly 7 digits
([regex]'\D(\d{7})$').Match($_).Groups[1].Value
}
Output:
1403036
1403036
1234567
This:
$path = 'C:\Users\3D Objects\1403036'
$result = ([regex]'\D(\d{7})(?:\D|$)').Match($path).Groups[1].Value
directly assigns the match to variable $result and will be the matching numeric value if it matches or $null. Regex method .Match() does not populate the $matches array.
Using the regex operator, which does populate the $matches array, you can also do this:
if ($path -match '\D(\d{7})(?:\D|$)') {
$result = $matches[1]
}
Regex details:
\D # Match a single character that is NOT a “digit” (any decimal number in any Unicode script)
( # Match the regex below and capture its match into backreference number 1
\d # Match a single character that is a “digit” (any decimal number in any Unicode script)
{7} # Exactly 7 times
)
(?: # Match the regular expression below
# Match this alternative (attempting the next alternative only if this one fails)
\D # Match a single character that is NOT a “digit” (any decimal number in any Unicode script)
|
# Or match this alternative (the entire group fails if this one fails to match)
$ # Assert position at the end of the string, or before the line break at the end of the string, if any (line feed)
)

Insert comma before a value if it is blank

Below is the data I have
-Ignored:31,Modified,src,data,all,*file,MINOSFIC/UTMNUP10
-Ignored:33,Modified,src,&,tgt,data,all,*file,MINOSFIC/UVEGAP10
-Ignored:92,Synchro,is,running,*file,MINOSFIC/VM010P50
-Ignored:01,Object,hold,(synchro),*file,MINOSFIC/VM010U51
here I am parsing the data and keeping in csv
for 1st and 2nd line it is working but when it is coming to 3rd and 4th line, it is pushing the column value one forward as there is no data before *file
Please let me know how to handle this. how to insert a comma before *file if there is not entry (like for first 2 line it is all)
$allIGfiles = Get-ChildItem -Path 'C:\LG2' -Recurse -Filter "*LG_VFN*"
foreach($file in $allIGfiles)
{
$filename = $file.FullName
$data = Get-Content $filename | Select -SkipLast 1
$Lines = #()
foreach ($line in $data){
if($line -match "Ignored")
{
$Lines+=$line
}
}
$NewLines = #($Lines | % { ($_ -replace "\s{2,}",",") -replace "(\d) ", '$1,'} )
$NewLines | Export-Csv 'c:\file.csv' -append -NoTypeInformation
Original data
-Ignored:31 Modified src data all *file MINOSFIC/UTMNUP10
-Ignored:33 Modified src & tgt data all *file MINOSFIC/UVEGAP10
-Ignored:92 Synchro is running *file MINOSFIC/VM010P50
-Ignored:01 Object hold (synchro) *file MINOSFIC/VM010U51
Update:
I am now getting the data like below but when i am trying to put it in csv it is only writing numbers to the file
-Ignored:31,Modified src data,all *file,MINOSFIC/UTMNUP10
-Ignored:33,Modified src & tgt data,all *file,MINOSFIC/UVEGAP10
-Ignored:92,Synchro is running,*file,MINOSFIC/VM010P50
-Ignored:01,Object hold (synchro),*file,MINOSFIC/VM010U51
-Ignored:01,Object hold (synchro),*file,MINOSFIC/VM010U52
-Ignored:01,Object hold (synchro),*file,MINOSFIC/VM010U53
-Ignored:01,Object hold (synchro),*file,MINOSFIC/VM010U54
Data with other code
Object OK (partial) 97% *file MINOSFIC/VM011P10
-Ignored:18 Object hold *file MINOSFIC/VM011P50
Object OK (partial) 78% *file MINOSFIC/VM800P30
*Error: 09 Diff. Creation date *file MINOSSVG/S100000702
*Error: 09 Diff. Creation date *file MINOSSVG/S100000805
-Ignored:18 Object hold *file MINOSSVG/S100001154
*Error: 09 Diff. Creation date *file MINOSSVG/S100001227
You could do this by using a regex that at first ignores the all value, but when constructing the comma separated new string, this will be inserted when found:
Read the file as string array
$data = Get-Content -Path $filename
I'm faking that by using a Here-String below:
$data = #"
-Ignored:31 Modified src data all *file MINOSFIC/UTMNUP10
-Ignored:33 Modified src & tgt data all *file MINOSFIC/UVEGAP10
-Ignored:92 Synchro is running *file MINOSFIC/VM010P50
-Ignored:01 Object hold (synchro) *file MINOSFIC/VM010U51
"# -split '\r?\n'
$result = foreach ($line in $data) {
if ($line -match '^(-Ignored:\d+)\s+(.+)\s+(\*file)\s+(.*)') {
'{0},{1},{2},{3},{4}' -f $matches[1],
($matches[2] -replace 'all$').Trim(),
($matches[2] -split '\s{2,}')[-1],
$matches[3],
$matches[4]
}
}
# output to console screen
$result
# write to file
$result | Set-Content -Path 'X:\TheNewFile.txt'
Output:
-Ignored:31,Modified src data,all,*file,MINOSFIC/UTMNUP10
-Ignored:33,Modified src & tgt data,all,*file,MINOSFIC/UVEGAP10
-Ignored:92,Synchro is running,,*file,MINOSFIC/VM010P50
-Ignored:01,Object hold (synchro),,*file,MINOSFIC/VM010U51
To also do this with *Error.. lines as in your updated example, change the line
if ($line -match '^(-Ignored:\d+)\s+(.+)\s+(\*file)\s+(.*)') {
into
if ($line -match '^((?:-Ignored|\*Error):\s*\d+)\s+(.+)\s+(\*file)\s+(.*)') {
Regex details:
^ Assert position at the beginning of a line (at beginning of the string or after a line break character)
( Match the regular expression below and capture its match into backreference number 1
(?: Match the regular expression below
Match either the regular expression below (attempting the next alternative only if this one fails)
-Ignored Match the characters “-Ignored” literally
| Or match regular expression number 2 below (the entire group fails if this one fails to match)
\* Match the character “*” literally
Error Match the characters “Error” literally
)
: Match the character “:” literally
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\d Match a single digit 0..9
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
( Match the regular expression below and capture its match into backreference number 2
. Match any single character that is not a line break character
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
( Match the regular expression below and capture its match into backreference number 3
\* Match the character “*” literally
file Match the characters “file” literally
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
( Match the regular expression below and capture its match into backreference number 4
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
One approach is to first replace two consecutive spaces with a comma. Then replace digit followed with a space with the same digit via capture group and a comma. Like so,
$data=#(
'-Ignored:31 Modified src data all *file MINOSFIC/UTMNUP10',
'-Ignored:33 Modified src & tgt data all *file MINOSFIC/UVEGAP10',
'-Ignored:92 Synchro is running *file MINOSFIC/VM010P50',
'-Ignored:01 Object hold (synchro) *file MINOSFIC/VM010U51')
$data | % { ($_ -replace "\s{2,}",",") -replace "(\d) ", '$1,'}
-Ignored:31,Modified src data,all *file,MINOSFIC/UTMNUP10
-Ignored:33,Modified src & tgt data,all *file,MINOSFIC/UVEGAP10
-Ignored:92,Synchro is running,*file,MINOSFIC/VM010P50
-Ignored:01,Object hold (synchro),*file,MINOSFIC/VM010U51
This would get all *file in same column as *file. Should that not be enough, use ConvertFrom-String or do another replacement to introduce the missing column. As of how, you probably need to calculate how many commas there are and deduct from that if the column is needed.

etc/host file entries match or not if not match entries then send a Triger

Here, I am new to PowerShell scripting. I am trying to do Host file entries should match every entry in a dynamic list of IP and DNS name entries from C:\Windows\System32\drivers\etc. Any mismatch will fail the audit.
entries are
10.23.24.45 foo.com
10.24.45.34 domain.com
Here is my code.
"$Pattern = '^(?<IP>\d{1,3}(\.\d{1,3}){3})\s+(?<Host>.+)$'
$File = "$env:SystemDrive\Windows\System32\Drivers\etc\hosts"
$Entries = #()
(Get-Content -Path $File) | ForEach-Object {
If ($_ -match $Pattern) {
$Entries += "$($Matches.IP) $($Matches.Host)"
Write-Host " the values are $Entries"
$FailureMessage = "IP and host entries are existing"
}
else {
$FailureMessage = "IP and host entries are doesn't existing"
}
}"
But this is not working for me. Can you help here
A hosts file can also contain comment lines or comments after the IP and Hostname parts, preceeded by a # character. Your regex at the moment does not account for that.
I would create a lookup hashtable with all required entries and use that to find whether the hosts file contains any of these or not and as result create an array of PSObjects for nice formatting and easy filtering.
Something like:
$file = "$env:SystemDrive\Windows\System32\Drivers\etc\hosts"
$pattern = '^\s*(?<IP>[0-9a-f.:]+)\s+(?<HostName>[^\s#]+)(?<Comment>.*)$'
# create an array of Hashtables with required entries
$required = #{Ip = '10.23.24.45'; HostName = 'foo.com'},
#{Ip = '10.24.45.34'; HostName = 'domain.com'}
# read the current content of the hosts file, filter only lines that match the pattern
$result = Get-Content -Path $file | Where-Object { $_ -match $pattern } | ForEach-Object {
$ip = $matches.Ip
$hostname = $matches.HostName
# test if the entry is one of the required ones
$exists = [bool]($required | Where-Object { $_.Ip -eq $ip -and $_.HostName -eq $hostname })
# output an object
[PsCustomObject]#{
IP = $ip
HostName = $hostname
Exists = $exists
}
}
# show results on screen
$result | Format-Table -AutoSize
Next you can send an email using Send-MailMessage if any of the required entries is missing
# select the entries where property Exists is False
$missing = $result | Where-Object { -not $_.Exists }
if ($missing) {
# here is where you send your mail message
}
Regex details:
^ Assert position at the beginning of a line (at beginning of the string or after a line break character)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
(?<IP> Match the regular expression below and capture its match into backreference with name “IP”
[0-9a-f.:] Match a single character present in the list below
A character in the range between “0” and “9”
A character in the range between “a” and “f”
One of the characters “.:”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
(?<HostName> Match the regular expression below and capture its match into backreference with name “HostName”
[^\s#] Match a single character NOT present in the list below
A whitespace character (spaces, tabs, line breaks, etc.)
The character “#”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
(?<Comment> Match the regular expression below and capture its match into backreference with name “Comment”
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
$ Assert position at the end of a line (at the end of the string or before a line break character)

Restructure text file using Powershell

I have an text file that is structured in the format below, I need to extract the Hostname, Stratum=x and Offset=y values into a structured format e.g. CSV. I intend to use the output to write windows event logs if the values meet certain thresholds. My thinking is that creating objects (e.g. the hostnames) and adding the stratum and offset values as members would allow me to achieve this, but my PowerShell skills fail me here..
___________________________________________________________________________
02/04/2020 08:11:00 : Started [TEST] Command Scrape
Text I don't care about
___________________________________________________________________________
Hostname_1 (192.168.1.254):
assID=0 status=0544 leap_none, sync_local_proto, 4 events, event_peer/strat_chg,
version="ntpd 4.2.2p1#1.1570-o Tue May 19 13:57:55 UTC 2009 (1)",
processor="x86_64", system="Linux/2.6.18-164.el5", leap=00, stratum=4,
precision=-10, rootdelay=0.000, rootdispersion=11.974, peer=59475,
refid=LOCAL(0),
reftime=d495c32c.0e71eaf2 Mon, Jan 7 2013 13:57:00.056, poll=10,
clock=d495c32c.cebd43bd Mon, Jan 7 2013 13:57:00.807, state=4,
offset=0.123, frequency=0.000, jitter=0.977, noise=0.977,
stability=0.000, tai=0
___________________________________________________________________________
Hostname_2 (10.10.1.1):
assID=0 status=0544 leap_none, sync_local_proto, 4 events, event_peer/strat_chg,
version="ntpd 4.2.2p1#1.1570-o Tue May 19 13:57:55 UTC 2009 (1)",
processor="x86_64", system="Linux/2.6.18-164.el5", leap=00, stratum=4,
precision=-10, rootdelay=0.000, rootdispersion=11.974, peer=59475,
refid=LOCAL(0),
reftime=d495c32c.0e71eaf2 Mon, Jan 7 2013 13:57:00.056, poll=10,
clock=d495c32c.cebd43bd Mon, Jan 7 2013 13:57:00.807, state=4,
offset=2.456, frequency=0.000, jitter=0.977, noise=0.977,
stability=0.000, tai=0
___________________________________________________________________________
Hostname_3 (10.10.1.2):
...
I found I can create the CSV if I manually reformat the data into keypairs (as below), using ConvertFrom-StringData and outputting to CSV;
(Get-Content 'file.txt' -Raw) -split '####' |
ForEach-Object {
$results = Convertform-StringData - StringData ($PSitem -replace '\n-\s+')
New-Object PSObject -Property $results | Select-Object Hostname, Stratum, Offset
} | Export-Csv 'file.csv' - NoTypeInformation
Hostname=Hostname_1
stratum=3
offset=-10.345
####
Hostname=Hostname_2
stratum=4
offset=-8.345
Becomes the following CSV:
"Hostname","Stratum","offset"
"Hostname_1","3","-10.345"
"Hostname_2","4","-8.345"
You could do this with the code below.
In your example, the text blocks are separated by a series of underscores. If in real life that is different, change the -split '_{2,}' accordingly.
$regex = '(?s)^\s*([\w_\d]+)\s+\(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\):.*stratum=(\d+).*offset=([\d.]+)'
$result = (Get-Content 'D:\file.txt' -Raw) -split '_{2,}' | Where-Object {$_ -match $regex} | ForEach-Object {
[PsCustomObject]#{
'Hostname' = $matches[1]
'Stratum' = $matches[2]
'Offset' = $matches[3]
}
}
# output to console
$result
#output to csv file
$result | Export-Csv -Path 'D:\file.csv' -NoTypeInformation
Output on screen:
Hostname Stratum Offset
-------- ------- ------
Hostname_1 4 0.123
Hostname_2 4 2.456
Output as CSV:
"Hostname","Stratum","Offset"
"Hostname_1","4","0.123"
"Hostname_2","4","2.456"
Regex details:
^ Assert position at the beginning of the string
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
( Match the regular expression below and capture its match into backreference number 1
[\w_\d] Match a single character present in the list below
A word character (letters, digits, etc.)
The character “_”
A single digit 0..9
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\( Match the character “(” literally
\d Match a single digit 0..9
{1,3} Between one and 3 times, as many times as possible, giving back as needed (greedy)
\. Match the character “.” literally
\d Match a single digit 0..9
{1,3} Between one and 3 times, as many times as possible, giving back as needed (greedy)
\. Match the character “.” literally
\d Match a single digit 0..9
{1,3} Between one and 3 times, as many times as possible, giving back as needed (greedy)
\. Match the character “.” literally
\d Match a single digit 0..9
{1,3} Between one and 3 times, as many times as possible, giving back as needed (greedy)
\) Match the character “)” literally
: Match the character “:” literally
. Match any single character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
stratum= Match the characters “stratum=” literally
( Match the regular expression below and capture its match into backreference number 2
\d Match a single digit 0..9
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
. Match any single character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
offset= Match the characters “offset=” literally
( Match the regular expression below and capture its match into backreference number 3
[\d.] Match a single character present in the list below
A single digit 0..9
The character “.”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
Fantastic, thank you so much. I've made the following adjustments to accommodate non-word characters in the hostname and offset, and exclude the trailing comma on the offset values.
$regex = '(?s)^\s*([\w_\d]+)\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):.*stratum=(\d+).*offset=([\d.]+)'
is now:
(?s)^\s*([\w|\W|\d]+)\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):.*stratum=(\d+).*offset=([\W|\d.][^,]

Read a file, count delimiters and output line number with mismatched delimiter

I have a file named: test_file.txt. The second line has 4 pipe delimiters and all other lines except 2nd line has 3 pipe delimiters.
I just want to output line 2 since it has one more delimiter than other lines.
$colCnt = "C:\test.txt"
[int]$LastSplitCount = $Null
Get-Content $colCnt | ?{$_} | Select -Skip 1 | %{if($LastSplitCount -and !
($_.split("|").Count -eq $LastSplitCount))
{"Process stopped at line number $($_.psobject.Properties.value[5]) for column count mis-match.";break}
elseif(!$LastSplitCount){$LastSplitCount = $_.split("|").Count}}
If your text file looks anything like this:
blah|using|three|delimiters
blah|using|four |delimiter |characters
blah|using|three|delimiters
blah|using|four |delimiter |characters
blah|using two |delimiters
The the following code should output the lines with more (or less) than 3 | delimiters:
$line = 0
switch -Regex -File "C:\test.txt" {
'^(?:[^|]*\|){3}[^|]*$' { $line++ } # this line is OK, just increase the line counter
default { "Bad delimiter count in line {0}: '{1}'" -f ++$line, $_ }
}
Output:
Bad delimiter count in line 2: 'blah|using|four |delimiter |characters'
Bad delimiter count in line 4: 'blah|using|four |delimiter |characters'
Bad delimiter count in line 5: 'blah|using two |delimiters'
Regex details:
^ Assert position at the beginning of the string
(?: Match the regular expression below
[^|] Match any character that is NOT a “|”
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\| Match the character “|” literally
){3} Exactly 3 times
[^|] Match any character that is NOT a “|”
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$ Assert position at the end of the string (or before the line break at the end of the string, if any)