Powershell sort string elements delimited by semicolons - powershell

I have a string wit a following content, delimited by semicolons:
echo $content
BCS3;BCS2;DigitalIO;GAElectricDrive;J1939;SKF15;UBloxGNSS;VIMS
Perhaps my question is noob, but I cannot figure out, how to sort this values alphabetically, e.g. I want to receive following output(first and second elements are not in alphabetical order):
BCS2;BCS3;DigitalIO;GAElectricDrive;J1939;SKF15;UBloxGNSS;VIMS

$Content = "BCS3;BCS2;DigitalIO;GAElectricDrive;J1939;SKF15;UBloxGNSS;VIMS"
$Content = ($Content -split ';'|Sort) -Join ';'
$content
BCS2;BCS3;DigitalIO;GAElectricDrive;J1939;SKF15;UBloxGNSS;VIMS
But the sorting is alphabetical, words containing numbers with differing places are sorted 1,10,100,2,20,200.
To avoid this you can use $ToNatural
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$Content = "1;10;100;2;20;200"
$Content = ($Content -split ';'|Sort $ToNatural) -Join ';'
$content
1;2;10;20;100;200

Related

Can I convert a row of comma delimited values to a column

I have one row of temperature data in a text file that I would like to convert to a single column and save as a CSV file using a PowerShell script. The temperatures are separated by commas and look like this:
21,22,22,22,22,22,22,20,19,18,17,16,15,14,13,12,11,10,9,9,9,8,8,9,8,8,8,9,9,8,8,8,9,9,9,8,8,8,8,8,9,10,12,14,15,17,19,20,21,21,21,21,21,21,21,21,21,21,21,20,20,20,20,20,22,24,25,26,27,27,27,28,28,28,29,29,29,28,28,28,28,28,28,27,27,27,27,27,29,30,32,32,32,32,33,34,35,35,34,33,32,32,31,31,30,30,29,29,28,28,27,28,29,31,33,34,35,35,35,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,38,39,40,42,43,43,43,43,43,42,42,42,41,41,41,41,40,39,37,36,35,34,33,32,31,31,31,31,31,31,31,31,31,31,
I have tried several methods based on searches in this forum I thought this might work but it returns an error: Transpose rows to columns in PowerShell
This is the modified code I tried that returns: Error: "Input string was not in a correct format."
$txt = Get-Content 'C:myfile.txt' | Out-String
$txt -split '(?m)^,\r?\n' | ForEach-Object {
# create empty array
$row = #()
$arr = $_ -split '\r?\n'
$k = 0
for ($n = 0; $n -lt $arr.Count; $n += 2) {
$i = [int]$arr[$n]
# if index from record ($i) is greater than current index ($k) append
# required number of empty fields
for ($j = $k; $j -lt $i-1; $j++) { $row += $null }
$row += $arr[$n+1]
$k = $i
}
$row -join '|'
}
This seems like it should be simple to do with only one row of data. Are there any suggestions on how to convert this single row of numbers to one column?
Try this:
# convert row to column data
$header = 'TEMPERATURE'
$values = $(Get-Content input.dat) -split ','
$header, $values | Out-File result.csv
#now test the result
Import-Csv result.csv
The header is the first line (or record) in the CSV file. In this case it's a single word, because there is only one column.
The values are the items between commas in the input. In this case, the -split on commas generates an array of strings. Note that, if comma is a separator, there will be no comma after the last temperature. Your data doesn't look like that, but I have assumed that the real data does.
Then, we just write the header and the array out to a file. But what happened to all the commas? It turns out that, for a single column CSV file, there are no commas separating fields. So the result is a simple CSV file.
Last, there is a test of the output using Import-csv to read the result and display it in table format.
This isn't necessarily the best way to code it, but it might help a beginner get used to powershell.
Assuming I'm understanding your intent correctly, based on your verbal description (not your own coding attempt):
# Create simplified sample input file
#'
21,22,23,
'# > myfile.txt
# Read the line, split it into tokens by ",", filter out empty elements
# with `-ne ''` (to ignore empty elements, such as would
# result from the trailing "," in your sample input),
# and write to an output CSV file with a column name prepended.
(Get-Content myfile.txt) -split ',' -ne '' |
ForEach-Object -Begin { 'Temperatures' } -Process { $_ } |
Set-Content out.csv
More concise alternative, using an expandable (interpolating) here-string:
# Note: .TrimEnd(',') removes any trailing "," from the input.
# Your sample input suggests that this is necessary.
# If there are no trailing "," chars., you can omit this call.
#"
Temperatures
$((Get-Content myfile.txt).TrimEnd(',') -split ',' -join [Environment]::NewLine)
"# > out.csv
out.csv then contains:
Temperatures
21
22
23

Append comma to every element in the Arraylist of strings

I need to append comma to every string , my code appending "," to last element as well how to eliminate that
for($j=0; $j -lt $back_log_bloblist.Count; $j++){
if($back_log_bloblist[$j].Name -like "$Value"){
$string += $back_log_bloblist[$j].Name +","
Write-Host $string
}
}
This can be solved much easier without an explicit loop:
$string = ($back_log_bloblist.Name -like $Value) -join ','
Explanation:
$back_log_bloblist.Name creates an array from the values of the Name property of all $back_log_bloblist elements
-like $Value selects all elements from this array that match pattern in $Value
-join ',' finally joins all selected elements (inserting commas only between elements, not after, exactly what you want)
you could remove the brackets, they are just there for conceptual clarity
Proof-of-concept:
$back_log_bloblist = [pscustomobject]#{ Name='foo' },
[pscustomobject]#{ Name='fop' },
[pscustomobject]#{ Name='bar' }
$Value = 'f*'
$string = ($back_log_bloblist.Name -like $Value) -join ','
$string
Output:
foo,fop

Retrieving second part of a line when first part matches exactly

I used the below steps to retrieve a string from file
$variable = 'abc#yahoo.com'
$test = $variable.split('#')[0];
$file = Get-Content C:\Temp\file1.txt | Where-Object { $_.Contains($test) }
$postPipePortion = $file | Foreach-Object {$_.Substring($_.IndexOf("|") + 1)}
This results in all lines that contain $test as a substring. I just want the result to contain only the lines that exactly matches $test.
For example, If a file contains
abc_def|hf#23$
abc|ohgvtre
I just want the text ohgvtre
If I understand the question correctly you probably want to use Import-Csv instead of Get-Content:
Import-Csv 'C:\Temp\file1.txt' -Delimiter '|' -Header 'foo', 'bar' |
Where-Object { $_.foo -eq $test } |
Select-Object -Expand bar
To address the exact matching, you should be testing for equality (-eq) rather than substring (.Contains()). Also, there is no need to parse the data multiple times. Here is your code, rewritten to to operate in one pass over the data using the -split operator.
$variable = 'abc#yahoo.com'
$test = $variable.split('#')[0];
$postPipePortion = (
# Iterate once over the lines in file1.txt
Get-Content C:\Temp\file1.txt | foreach {
# Split the string, keeping both parts in separate variables.
# Note the backslash - the argument to the -split operator is a regex
$first, $second = ($_ -split '\|')
# When the first half matches, output the second half.
if ($first -eq $test) {
$second
}
}
)

powershell split keeping only the 2 first part of string

i'm new in powershell
i have a file that contains OU paths separates by "/"
i'd like to only keep the 2 first element of each string
example:
paris/sales/salers/14tharrdt
london/comptability/office1
would give
paris/sales
london/comptability
i googled and found many things, but no way to do this simple thing
thanks for help
You could use -split to split the string on the \ character, select the first two elements and join them together:
$content = Get-Content 'your_file_path'
$content | foreach {
($_ -split '/')[0, 1] -join '/'
}
$content | Set-Content 'your_file_path'
Or, if you prefer using regex here a solution without split (demo here):
$content = Get-Content 'your_file_path'
$content | foreach {
$_ -replace '(.*?\/[^\/]+).*', '$1'
}
$content | Set-Content 'your_file_path'
Like:
$a = "paris/sales/salers/14tharrdt"
$b = $a.Split("/")[0] + "/" + $a.Split("/")[1]
$b
Improvement would be if call Split once and save it to a variable

Powershell: Find and replace words split by newline

So I have a text file that looks something like this:
Members : {USER\member1, USER\member2, US
ER\member3, USER\member4, USER
\member5, USER\member6}
and I would like to remove USER\. The following code removes it but not when it's split by a newline, for example when US on one line and ER\ on another line.
Foreach-Object { %{$_.Replace('USER\', '') }
Putting `n or `r in there doesn't work. Any help is appreciated.
Try this:
PS > ((Get-Content .\t.txt) | % { $_.Trim() }) -join "" -replace "USER\\"
Members : {member1, member2, member3, member4, member5, member6}
If the text is in a string-array, switch out (Get-Content .\t.txt) with your variable. If you have the text in a string(not array) variable, use:
($MYSTRINGVAR.Split("`r`n") | % { $_.Trim() }) -join "" -replace "USER\\"
EDIT Just modify the "Members" part:
$text = (Get-Content .\input.txt) -join "`r`n"
($text | Select-String '(?s)(?<=Members : \{)(.+?)(?=\})' -AllMatches).Matches | % {
$text = $text.Replace($_.Value, ($_.Value -split "`r`n" | % { $_.Trim() }) -join "" -replace "USER\\")
}
$text | Set-Content output.txt
There are probably easier ways to get there, but you can give this one a try:
$Text = #'
Members : {USER\member1, USER\member2, US
ER\member3, USER\member4, USER
\member5, USER\member6}
'#
# First - USER\ with newline inside..
foreach ($index in 1..4) {
$Text = $Text -replace ('USER\\'.Insert($index,'(\r\n\s+)')), '$1'
}
# Than - pure USER\
$Text = $Text -replace 'USER\\'
$Text
As you can see I create few patterns that contain and keep that element in results (, '$1'). For simple ones - I just remove USER\
I've used herestring to create text to work with, it's possible that \r may not be needed for actual file.
This is actually just a comment to Graimer's solution, but it would've been too long and also not readable enough as a comment, so I'm making it a (supplementary) answer instead.
To re-wrap the string after removing USER\ you could do something like this:
$s = "Members : {member1, member2, member3, member4, member5, member6}"
$s -match '^(.*?{)(.*)(})$'
$pad = " " * $matches[1].Length
$matches[1] + ($matches[2] -replace '(.{1,20},) ', "`$1`r`n$pad") + $matches[3]
The first regular expression splits the string into 3 parts that can be accessed via the $matches collection:
Name Value
---- -----
3 }
2 member1, member2, member3, member4, member5, member6
1 Members : {
0 Members : {member1, member2, member3, member4, member5, member6}
$matches[1] is the prologue including the opening curly bracket, $matches[2] is the member list, and $matches[3] is the closing curly bracket. Now you only need to wrap $matches[2] at whatever length you want:
'(.*{1,20},) '
The above means "longest match of at most 20 characters followed by a comma and a space". Replace that with the 1st group ($1) followed by a line-break (```rn``) and a number of spaces that matches the length of the prologue ($pad`) and glue it back together with prologue and trailing curly bracket.