Home > Software engineering >  How to save in array all positions of certain character in a string?
How to save in array all positions of certain character in a string?

Time:06-24

I have a string that contains numerous slashes, for example: $message = ab/cde/f/ghijklm/no/p

I'd like to have a function which when run on this $message will return a $slash_array with the values of the position of all the slashes.

ie, in my example above, I would have :

PS > Write-Output $slash_array
3,7,9,17,20

Then I want to use these values to insert a slash after every character except if it's at one of these positions (I don't want the program to add a slash after an already existing slash).

CodePudding user response:

Just loop through the characters and check then return the index

PS C:\> $message = "ab/cde/f/ghijklm/no/p"
PS C:\> $slash_array = for ($i = 0; $i -lt $message.Length; $i  )
                           { if ($message[$i] -eq '/') { $i   1 } }
PS C:\> $slash_array
3
7
9
17
20
PS C:\> $slash_array -join ', '
3, 7, 9, 17, 20
PS C:\>

But if you just want to insert a slash after any non-slash character why don't just do a regex match then replace?

PS C:\> $message -replace '([^/])(?!/)', '$1/'
a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/

([^/])(?!/) matches a non-slash character that's not followed by a slash, then add a slash after the matched character

Some other alternatives:

PS C:\> ($message.ToCharArray() | Where-Object { $_ -ne '/' }) -join '/'
a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p
PS C:\> $message.Replace("/", "").ToCharArray() -join '/'
a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p

CodePudding user response:

As Theo points out, since your intent is to separate all individual characters other than a slash (/) with /, you don't need to find the indices of existing slashes, because the approach can be simplified to:

  • removing existing / instances, using the -replace operator

  • joining the individual characters in the result with the -join operator

    • The array of individual characters is obtained with the .ToCharArray() .NET string method below; alternatively, you could cast to [char[]]
# -> 'a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p'
('ab/cde/f/ghijklm/no/p' -replace '/').ToCharArray() -join '/'

As zett42 points out, the most direct way to obtain - 0-based - character or substring positions, is to use the [regex]::Matches() .NET method:

# -> 2, 6, 8, 16, 19
[regex]::Matches('ab/cde/f/ghijklm/no/p', '/').Index

Note that even though the method call returns multiple (a collection of) match-information objects, .Index can be used to extract the index (position) value from each, courtesy of PowerShell's convenient member-access enumeration feature.

  • Related