I would like to remove a empty line in using powershell.
Here is my Text
Line 1
Line 2
<Empty line>
<Empty line>
Line 3
Line 4
I have tried using -replace ("`n", "") but it does not work.
Please help!
$text = """
Line 1
Line 2
Line 3
Line 4
"""
$text -replace "(?m)^\s*`r`n",''
# Or
$text -replace "(?m)^\s*`n",''
regex explained:
(?m) set the multiline flag so ^ matches the beginning of each line and not just the begining of the whole string.
^ matches the beginning of a line
\s* matches any number of white spaces (could also be 0 white spaces)
`r`n matches the end of a line.
Why `r`n or just `n (depending on the machine or file):
\`r = CR (Carriage Return) → Used as a new line character in Mac OS before X
\`n = LF (Line Feed) → Used as a new line character in Unix/Mac OS X
\`r\`n = CR + LF → Used as a new line character in Windows
Or simply read the file as string array and use a Where-Object to let pass only the lines that contain at least one non-whitespace character.
$text = Get-Content -Path 'D:\Thefile.log' |
Where-Object { $_ -match '\S' }
Now you can save this string array in $text back to file, join it with [environment]::NewLine to become a single string again, or...
Related
Lets say I have a text file whose content is this:
======= Section 1 ==========
This is line one
This is line two
This is line three
======= Section 2 ==========
This is line Four
This is line Five
This is line Six
I import it into Powershell using $SourceFile = Get-Content '.\source.txt' -Delimiter '==='
then clean it up with $Objects = $SourceFile -replace '^=.*', ''
I now have this $Objects array that has:
This is line one
This is line two
This is line three
and
This is line Four
This is line Five
This is line Six
What I really want to know is how can I wrap a specific line in double quotes or parenthesis etc, so that specific line in all the objects arrays are also handled the same way.
For example line 3 of both arrays should have double quotes wrapped around them:
This is line one
This is line two
"This is line three"
and
This is line Four
This is line Five
"This is line Six"
I have tried many things, closest I got was $test = $objects -replace 'This is line three', '"This is line three"' As you can see this is less than ideal for an object of many arrays.
I am still fairly new to Powershell, any help would be greatly appreciated
Assuming that you want to wrap the 3rd line in each block in double quotes:
# Read the input file and split it into blocks of lines by a
# regex matching the section lines (without including the section lines).
(Get-Content -Raw file.txt) -split '(?m)^===.*\r?\n' -ne '' |
ForEach-Object { # Process each block of lines (multi-line string)
# Split this block into individual lines, ignoring a trailing newline.
$linesInBlock = $_ -replace '\r?\n\z' -split '\r?\n'
# Modify the 3rd line.
$linesInBlock[2] = '"{0}"' -f $linesInBlock[2]
# Output the lines, including the modification.
Write-Verbose -Verbose "-- next block"
$linesInBlock
}
Output with your sample input:
VERBOSE: -- next block
This is line one
This is line two
"This is line three"
VERBOSE: -- next block
This is line Four
This is line Five
"This is line Six"
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)
I need to add the quotation mark to a text file that contains 500 lines text.
The format is inconsistent. It has dashes, dots, numbers, and letters. For example
1527c705-839a-4832-9118-54d4Bd6a0c89
16575getfireshot.com.FireShotCaptureWebpageScreens
3EA2211E.GestetnerDriverUtility
I have tried to code this
$Flist = Get-Content "$home\$user\appfiles\out.txt"
$Flist | %{$_ -replace '^(.*?)', '"'}
I got the result which only added to the beginning of a line.
"Microsoft.WinJS.2.0
The expected result should be
"Microsoft.WinJS.2.0"
How to add quotation-mark to the end of each line as well?
There is no strict need to use a regex (regular expression) in your case (requires PSv4+):
(Get-Content $home\$user\appfiles\out.txt).ForEach({ '"{0}"' -f $_ })
Array method .ForEach() processes each input line via the script block ({ ... }) passed to it.
'"{0}"' -f $_ effectively encloses each input line ($_) in double quotes, via -f, the string-format operator.
If you did want to use a regex:
(Get-Content $home\$user\appfiles\out.txt) -replace '^|$', '"'
Regex ^|$ matches both the start (^) and the end ($) of the input string and replaces both with a " char., effectively enclosing the input string in double quotes.
As for what you tried:
^(.*?)
just matches the very start of the string (^), and nothing else, given that .*? - due to using the non-greedy duplication symbol ? - matches nothing else.
Therefore, replacing what matched with " only placed a " at the start of the input string, not also at the end.
You can use regex to match both:
The beginning of the line ^(.*?)
OR |
The End of the line $
I.e. ^(.*?)|$
$Flist = Get-Content "$home\$user\appfiles\out.txt"
$Flist | %{$_ -replace '^(.*?)|$', '"'}
Say I have a text file 123.txt
one,two,three
four,five,six
My goal is to capitalize the first character of each line by using Get-Culture. This is my attempt:
$str = gc C:\Users\Administrator\Desktop\123.txt
#Split each line into an array
$array = $str.split("`n")
for($i=0; $i -lt $array.Count; $i++) {
#Returns O and F:
$text = (Get-Culture).TextInfo.ToTitleCase($array[$i].Substring(0,1))
#Supposed to replace the first letter of each array with $text
$array[$i].Replace($array[$i].Substring(0,1), $text) >> .\Desktop\finish.txt
}
Result:
One,twO,three
Four,Five,six
I understand that .Replace() is replaces every occurrence of the current array, which is why I made sure that it's replacing ONLY the first character of the array with $array[$i].Substring(0,1), but this doesn't work.
Try the following:
Get-Content C:\Users\Administrator\Desktop\123.txt | ForEach-Object {
if ($_) {
$_.Substring(0, 1).ToUpper() + $_.Substring(1)
} else {
$_
}
} > .\Desktop\finish.txt
Get-Content reads the input file line by line and sends each line - stripped of its line terminator - through the pipeline.
ForEach-Object processes each line in the associated script block, in which $_ represents the line at hand:
if ($_) tests if the line is nonempty, i.e. if there's at least 1 character; if not, the else block simply passes the empty line through.
$_.Substring(0, 1).ToUpper() converts the line's 1st character to uppercase, implicitly using the current culture (with a single character, this is equivalent to applying Get-Culture).TextInfo.ToTitleCase()).
+ $_.Substring(1) appends the rest of the line.
Only > rater than >> is needed to write to the output file, because the entire pipeline's output is written at once.
The reason this is not working is because you are replacing the character...
$array[$i].Substring(0,1)
... but you are using the Replace method on the entire array element
$array[$i].Replace(...
Here the array element is a string, equal to a line of the input. So it will replace every occurrence of that character.
Get-Content (unless you use the -Raw parameter) by default returns the text as an array of strings. So you should be able to use this regex replace (I have used ToString().ToUpper() - nothing wrong with the Get-Culture method)
$str = gc C:\Users\Administrator\Desktop\123.txt
foreach($line in $str){
$line -replace '^\w', $line[0].ToString().ToUpper() >> .\Desktop\finish.txt
}
Regex explanation:
^ is an anchor. It specifies "the beginning of the string"
\w matches a word character - usually a-z, A-Z, 0-9
See mklement0's comments here for the more focused ^\p{Ll} and here for further explanation
I have a text file and want to replace the text between 2 lines. This is working OK until there is no text between the two lines.
my code:
$File = "D:\test.txt"
$NewLine = "newline with some text"
$text = Get-Content "D:\test.txt" -raw
$text -replace ('(?m)(.*)^Line 3[\r\n]+Line 4([\r\n])', $NewLine) |
Out-File $File -Force
Text files:
Text file that does work:
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Text file that does NOT work:
Line 1
Line 2
Line 3
Some text here
Line 4
Line 5
Line 6
What I am doing wrong?
The issue you have is that your Regular Expression (RegEx for short) does not allow for anything between Line 3 and Line 4. Here's what you're using (cleaned up a tiny bit):
(?m)^Line 3[\r\n]+Line 4[\r\n]
Let us break that down just a little bit. (?m) puts the RegEx engine into multi-line mode, so it will allow you to use the carat ^ to indicate the beginning of a line, instead of just the beginning of the string. There's other things it does, but that's what you are using it for. I discarded the (.*), because it is pointless. So you have a carat indicating the beginning of a line, followed by the text Line 3, and then [\r\n]+ which will find the end of the line. Then it finds Line 4, immediately followed by the end of that line. This is why it fails when there is text, you didn't allow for any additional text. To do that you can use .*?. What that means is this: The dot indicates any character, doesn't matter if it's letter, number, symbol, or even a character that doesn't register on the screen. The asterisk * indicates that there needs to be zero or more of that, so zero or more of any character. The question mark tells it to look for zero or more, but to match as few characters as possible before moving on in the pattern, so it will only match things until it can move on to Line 4[\r\n]. The functional pattern would be:
(?m)^Line 3[\r\n]+.*?[\r\n]Line 4[\r\n]
Corrected your regex here to capture only Line 3 and Line 4 with the text inbetween.
$File = 'D:\test.txt'
$NewLine = 'newline with some text'
$text = Get-Content -Path 'D:\test.txt' -Raw
$Pattern = '(?m)^Line\s3[\r\n]+.*?Line\s4'
$text -replace $Pattern,$NewLine |
Out-File -FilePath $File -Force