PowerShell replace text in string after certain expression - powershell

I am trying to replace everything in a string after a certain expression is found: In this case ",=dc".
Im kinda new to PowerShell so would appreciate any help. My code only replaces any ",=dc" but not what is behind that
$array += #()
$array += "vu=doc,vu=noc,dc=zet,dc=zez"
$array += "vu=doc,vu=nud,dc=gut,dc=zrt"
$array += "vu=doc,vu=nud,vu=dit,dc=gut,dc=zrt,dc=opt"
foreach ($value in $array){
$arraytype -replace "(?<=(,=dc)).*"
}
I want to only get back the "vu=doc,vu=noc"-part. Everything after the first ",=dc" should be deleted.

It's easier to use an indexed loop if you want the values in the array updated. Also, You can define an array simply by using a comma between the elements. Avoid concatenating with += as this means every time the entire array needs to be recreated in memory, which is both time and memory consuming.
Try
$array = "vu=doc,vu=noc,dc=zet,dc=zez",
"vu=doc,vu=nud,dc=gut,dc=zrt",
"vu=doc,vu=nud,vu=dit,dc=gut,dc=zrt,dc=opt"
for ($i = 0; $i -lt $array.Count; $i++) {
$array[$i] = ($array[$i] -replace 'dc=[^,]+,?').TrimEnd(",")
}
$array
Result:
vu=doc,vu=noc
vu=doc,vu=nud
vu=doc,vu=nud,vu=dit
Regex details:
dc= Match the character string “dc=” literally (case insensitive)
[^,] Match any character that is NOT a “,”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
, Match the character “,” literally
? Between zero and one times, as many times as possible, giving back as needed (greedy)

You can use IndexOf method to find the position of the string and use Substring method to slice the string up to that position.
$array = #()
$array += "vu=doc,vu=noc,dc=zet,dc=zez"
$array += "vu=doc,vu=nud,dc=gut,dc=zrt"
$array += "vu=doc,vu=nud,vu=dit,dc=gut,dc=zrt,dc=opt"
foreach ($value in $array){
$index = $value.IndexOf(",dc=")
if($index -eq -1) {
Write-Output $value
} else {
Write-Output $value.Substring(0, $index)
}
}
Note: I think you have a typo in the first line($array = #())

Related

Find index of array where condition is true in PowerShell [duplicate]

I have trouble of getting index of the current element for multiple elements that are exactly the same object:
$b = "A","D","B","D","C","E","D","F"
$b | ? { $_ -contains "D" }
Alternative version:
$b = "A","D","B","D","C","E","D","F"
[Array]::FindAll($b, [Predicate[String]]{ $args[0] -contains "D" })
This will return:
D
D
D
But this code:
$b | % { $b.IndexOf("D") }
Alternative version:
[Array]::FindAll($b, [Predicate[String]]{ $args[0] -contains "D" }) | % { $b.IndexOf($_) }
Returns:
1
1
1
so it's pointing at the index of the first element. How to get indexes of the other elements?
You can do this:
$b = "A","D","B","D","C","E","D","F"
(0..($b.Count-1)) | where {$b[$_] -eq 'D'}
1
3
6
mjolinor's answer is conceptually elegant, but slow with large arrays, presumably due to having to build a parallel array of indices first (which is also memory-inefficient).
It is conceptually similar to the following LINQ-based solution (PSv3+), which is more memory-efficient and about twice as fast, but still slow:
$arr = 'A','D','B','D','C','E','D','F'
[Linq.Enumerable]::Where(
[Linq.Enumerable]::Range(0, $arr.Length),
[Func[int, bool]] { param($i) $arr[$i] -eq 'D' }
)
While any PowerShell looping solution is ultimately slow compared to a compiled language, the following alternative, while more verbose, is still much faster with large arrays:
PS C:\> & { param($arr, $val)
$i = 0
foreach ($el in $arr) { if ($el -eq $val) { $i } ++$i }
} ('A','D','B','D','C','E','D','F') 'D'
1
3
6
Note:
Perhaps surprisingly, this solution is even faster than Matt's solution, which calls [array]::IndexOf() in a loop instead of enumerating all elements.
Use of a script block (invoked with call operator & and arguments), while not strictly necessary, is used to prevent polluting the enclosing scope with helper variable $i.
The foreach statement is faster than the Foreach-Object cmdlet (whose built-in aliases are % and, confusingly, also foreach).
Simply (implicitly) outputting $i for each match makes PowerShell collect multiple results in an array.
If only one index is found, you'll get a scalar [int] instance instead; wrap the whole command in #(...) to ensure that you always get an array.
While $i by itself outputs the value of $i, ++$i by design does NOT (though you could use (++$i) to achieve that, if needed).
Unlike Array.IndexOf(), PowerShell's -eq operator is case-insensitive by default; for case-sensitivity, use -ceq instead.
It's easy to turn the above into a (simple) function (note that the parameters are purposely untyped, for flexibility):
function get-IndicesOf($Array, $Value) {
$i = 0
foreach ($el in $Array) {
if ($el -eq $Value) { $i }
++$i
}
}
# Sample call
PS C:\> get-IndicesOf ('A','D','B','D','C','E','D','F') 'D'
1
3
6
You would still need to loop with the static methods from [array] but if you are still curious something like this would work.
$b = "A","D","B","D","C","E","D","F"
$results = #()
$singleIndex = -1
Do{
$singleIndex = [array]::IndexOf($b,"D",$singleIndex + 1)
If($singleIndex -ge 0){$results += $singleIndex}
}While($singleIndex -ge 0)
$results
1
3
6
Loop until a match is not found. Assume the match at first by assigning the $singleIndex to -1 ( Which is what a non match would return). When a match is found add the index to a results array.

Powershell - output a foreach loop to one line

I am trying to take the output of my foreach loop and apply the array to a string that reads on one line. Here is my code so far:
$upper = 65..90
$lower = 97..122
foreach ($i in $upper)
{
[char]$i
}
foreach ($i in $lower)
{
[char]$i
}
I'm guessing I need to convert the output of the scriptblock to a variable and use the -join option, but everywhere I look I'm struggling to find how to structure that. Any guidance would be appreciated.
For this particular case, ForEach(type convertToType) is very useful, here is a cool way to get your lower and upper case dictionary string:
$lowerDict = [string]::new(([int][char]'a'..[int][char]'z').ForEach([char]))
$upperDict = $lowerDict.ToUpper()
If you have access to PowerShell Core, it can be reduced to:
$lowerDict = [string]::new('a'..'z')
$upperDict = $lowerDict.ToUpper()
As for what you are struggling on, how to do it with what you currently have (a foreach loop). You can capture all the output from the loop first:
$upper = foreach ($i in 65..90) { [char]$i }
Now, $upper is an array of chars, then to convert it to string, you can either use -join (guessed right) or [string]::new(...) as I did on my previous example:
$upperDict = -join $upper
# OR
$upperDict = [string]::new($upper)

Trim Values inside (one array inside (twoDimentionalArray))

I'm trying to remove the leading 0's in all values of an array within a two dimensional array.
Is there a library that can do this for me? I tried it with a foreach loop, but it only trims the current temp variable.
Here is the code:
[String[]]$arr1 = #('str1','str2','str3')
[String[]]$arr2 = #('str4','str5','str6')
[String[]]$arr3 = #('0str7')
[System.Object[]]$twoDimensionalArray = #()
[System.Object[]]$twoDimensionalArray += ,($arr1)
[System.Object[]]$twoDimensionalArray += ,($arr2)
[System.Object[]]$twoDimensionalArray += ,($arr3)
Write-Host "Removing leading zeros from array in twoDimentionalArray..."
ForEach ($strValue in $twoDimensionalArray[2])
{
$strValue = $strValue.TrimStart('0')
}
Write-Host "Leading zero's are removed."
Write-Host ""
Write-Host '$strValue =' $strValue
Write-Host '$twoDimensionalArray[2] =' $twoDimensionalArray[2]
Write-Host ""
Output (0str7)
Removing leading zeros from array in twoDimentionalArray...
Leading zero's are removed.
$strValue = str7
$twoDimensionalArray[2] = 0str7
Desired Output (str7)
Removing leading zeros from array in twoDimentionalArray...
Leading zero's are removed.
$strValue = str7
$twoDimensionalArray[2] = str7
Any ideas?
Here is the modified code snippet with the desired output. The trick is to modify the object itself:
[String[]]$arr1 = #('str1','str2','str3')
[String[]]$arr2 = #('str4','str5','str6')
[String[]]$arr3 = #('0str7')
[System.Object[]]$twoDimensionalArray = #()
[System.Object[]]$twoDimensionalArray += ,($arr1)
[System.Object[]]$twoDimensionalArray += ,($arr2)
[System.Object[]]$twoDimensionalArray += ,($arr3)
Write-Host "Removing leading zeros from array in twoDimentionalArray..."
[int] $arrayCounter = 0
ForEach ($strValue in $twoDimensionalArray[2])
{
$twoDimensionalArray[2][$arrayCounter] = $strValue.TrimStart('0')
$arrayCounter++
}
Write-Host "Leading zero's are removed."
Write-Host ""
Write-Host '$strValue =' $strValue
Write-Host '$twoDimensionalArray[2] =' $twoDimensionalArray[2]
Write-Host ""
I have tested this and it outputs str7 as you are expecting.
Edit all of the jagged array
This might be considered cheating and I don't know if you actual use case will abide by this but I tried to make it a little easier by using an array operator on this jagged array.
$twoDimensionalArray = $twoDimensionalArray | Foreach-object{
,($_ -replace "^0+")
}
This should save back to the original array $twoDimensionalArray. Using -replace save us running a separate loop to going inside the other array.
What this will do is use regex to replace all leading zeros from the array elements. Since the array would then be unrolled we still need the unary operator to ensure that the data is sent down the pipe as an array.
Depending on what control you have on your input this could be simplified as
$arr1 = #('str1','str2','str3')
$arr2 = #('str4','str5','str6')
$arr3 = #('0str7')
[string[]]$twoDimensionalArray = $arr1, $arr2, $arr3 | ForEach-Object{
,($_ -replace "^0+")
}
Edit only one element of the jagged array
Very simple change to get that running using the above logic.
$elementToChange = 2
$twoDimensionalArray[$elementToChange] = [String[]]#($twoDimensionalArray[$elementToChange] -replace "^0+")

How to declare and get array value

I am new to Powershell, first time using it.
I have declared an array and use array value but using below code, I am not able to retrieve the array value...Any idea what I am missing here?
Just FYI.. I am executing script in ADOBE ILLUSTRATOR and for testing I am using 3 here in condition (for loop)... will use $array later
$array = "a.jpg","b.jpg","c.jpg";
for ($i=1; $i-le=3; $i++)
{
$.writeln("This is line number " + $array[$i]);
var targetFileName = $array[$i]+'.png';
$.writeln(targetFileName);
}
I tried $array[$i].toString() as well but still not getting values... I am getting 0
Any help is appreciated and thanks in advance to all for your help
for ($i=1; $i-le=3; $i++)
The condition in the above line doesn't have a valid comparison operator. Change that to
for ($i=1; $i -le 3; $i++)
if you want the loop to terminate after 3 cycles.
$.writeln("This is line number " + $array[$i]);
var targetFileName = $array[$i]+'.png';
$.writeln(targetFileName);
This is not valid PowerShell. Looks more like JavaScript to me. In PowerShell it should probably look like this:
Write-Output "This is line number $i"
$targetFileName = $array[$i] + '.png'
Write-Output $targetFileName
or shorter
"This is line number $i"
$array[$i] + '.png'
Note that PowerShell arrays are zero-based, so the last iteration ($array[3]) will return $null instead of an element from the array. If you want to iterate over the elements of the array you should change your loop to this:
for ($i=0; $i -lt $array.Length; $i++) {
"This is line number $($i+1)"
$array[$i] + '.png'
}
or (better) pipe your array into a foreach loop:
$i = 0
$array | % {
"This is line number " + ++$i
$_ + '.png'
}

Error with Substring Code - Powershell

I'm getting errors with the code below. I'm trying to take lines in a text file that are over 180 characters and parse them to a new line. I have to take the first 22 characters and put it in from of part two since it contains inital data that's needed on the line:
$data = get-content "C:\TestFile.txt"
$strAcct= #()
$strPart1= #()
$strPart2= #()
$strLength= #()
foreach($line in $data)
{
if ( $line.length -gt 181)
{ $strLength = $line.length
$strAcct += $line.substring(0,22)
$strPart1 += $line.substring(0,180)
$strPart2 += $line.substring(181,$strLength)
Add-Content "C:\TestFile-Output.txt" $strPart1
Add-Content "C:\TestFile-Output.txt" $strAcct $strPart2
}
Else {
Add-Content "C:\TestFile-Output.txt" $line
}
}
Substring takes an index, and the number of characters to take starting from that index. Your third substring bombs, because you are trying to take more characters than there are in the string. Change it to $strLength - 181, or alternatively, you can leave the second parameter out entirely, to just take the rest of the string starting from the index in the first parameter.
Change this:
$line.substring(181, $strLength)
to this:
$line.substring(181)
or even this:
$line.substring(181, $strLength - 181)