I've got a CSV file full of filepaths like below:
D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\Images
D:\CompanyData\REPORTS\ENQUIRIES\Quay House\Text
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\Photography
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\Reports\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\Reports\Images
I want to split them on the 5th '/' character to return the following (including the last trailing '/'
D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\
D:\CompanyData\REPORTS\ENQUIRIES\Quay House\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\
So far I've tried the following:
$source = $Item.Source.Split("\")[0]
And various other combinations of the above but can't quite get what I'm after. Can anyone assist?
Try like this:
[string](Split-Path "PATH")+"\"
If you have $Item.Source then:
[string](Split-Path "$($Item.Source)")+"\"
Here is another solution using Select-String
(Note, that the pattern uses regex, so you need to escape the backslash \ with another backslash \)
$source = ($($Item.Source) | Select-String -Pattern '.+\\.+\\.+\\.+\\.+\\' -AllMatches).Matches.Value
Output:
D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\
D:\CompanyData\REPORTS\ENQUIRIES\Quay House\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\Reports\
D:\CompanyData\REPORTS\ENQUIRIES\Church Road\Reports\
You can split each file path on the backslash to get an array of parts. Then join a maximum of 5 parts with a backslash and append another backslash tyo that:
$parts = "D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\Images" -split '\\'
'{0}\' -f ($parts[0..[math]::Min($parts.Count, 4)] -join '\')
Or do this with regex:
"D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\Images" -replace '^(([^\\]+\\){1,5}).*', '$1'
Regex details:
^ Assert position at the beginning of the string
( Match the regular expression below and capture its match into backreference number 1
( Match the regular expression below and capture its match into backreference number 2
[^\\] Match any character that is NOT a “A \ character”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\\ Match the character “\” literally
){1,5} Between one and 5 times, as many times as possible, giving back as needed (greedy)
)
. 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)
Result:
D:\CompanyData\REPORTS\ENQUIRIES\Old House Farm\
Simple regex version:
$Item.Source -replace "(('[^\\]+\\){1,5}).*", '$1'
[^\\]+\\ matches 1-n non-\ followed by \
{1,5} repeat the pattern 5 times
Related
So lets say I have a multi line string as below.
#abc
abc def
abc
I want to only replace the first instance of abc that starts on a new line with xyz while ignoring any whitespaces that might precede it (like in the above example)
So my replaced string should read
#abc
xyz def
abc
Not very good at regex so would appreciate suggestions. Thanks!
To do that, you need a regular expression that anchors to the beginning of a line, allows for multiple leading whitespaces and uses a word boundary to make sure you do not replace part of a larger string.
$multilineText = #"
#abc
abc def
abc
"#
$toReplace = 'abc'
$replaceWith = 'xyz'
# create the regex string.
# Because the example `abc` in real life could contain characters that have special meaning in regex,
# you need to escape these characters in the `$toReplace` string.
$regexReplace = '(?m)^(\s*){0}\b' -f [regex]::Escape($toReplace)
# do the replacement and capture the result to write to a new file perhaps?
$result = ([regex]$regexReplace).Replace($multilineText, "`$1$replaceWith", 1)
# show on screen
$result
The above works Case-Sensitive, but if you do not want that, simply change (?m) into (?mi) in the $regexReplace definition.
Output:
#abc
xyz def
abc
Regex details:
(?m) Match the remainder of the regex with the options: ^ and $ match at line breaks (m)
^ 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
\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)
){0}
\b Assert position at a word boundary
Special Characters in Regex
Char
Description
Meaning
\
Backslash
Used to escape a special character
^
Caret
Beginning of a string
$
Dollar sign
End of a string
.
Period or dot
Matches any single character
|
Vertical bar or pipe symbol
Matches previous OR next character/group
?
Question mark
Match zero or one of the previous
*
Asterisk or star
Match zero, one or more of the previous
+
Plus sign
Match one or more of the previous
( )
Opening and closing parenthesis
Group characters
[ ]
Opening and closing square bracket
Matches a range of characters
{ }
Opening and closing curly brace
Matches a specified number of occurrences of the previous
The 1 just replaces the first instance of 'abc' with 'xyz' within a string.
Write-Host "Replace Example One" -ForegroundColor Yellow -BackgroundColor DarkGreen
$test = " abc def abc "
[regex]$pattern = "abc"
$pattern.replace($test, "xyz", 1)
Write-Host "Replace Example Two" -ForegroundColor Green -BackgroundColor Blue
$test = Get-Content "c:\test\text.txt"
[regex]$pattern = "abc"
$x = $pattern.replace($test, "xyz", 1)
Write-Host $x
Write-Host "Replace Example Three" -ForegroundColor White -BackgroundColor Red
$multilineText = #"
#abc
abc def
abc
"#
[regex]$pattern = "abc"
$y = $pattern.replace($multilineText, "xyz", 1)
Write-Host $y
Here is what I have.
get-childitem "\\myfileserver\out\*" | foreach { rename-item $_ $_.Name.Replace("_123456_837P.", ".").Replace(".test.", ".sa.").Replace("_987654_837I." , ".") }
Here is the filename I want to fix
999_987654_837I.74161.test
I want to remove _987654_837I from the file name. I was just going to rename it but those numbers may change. So now I want to remove the 4th character starting at the _ and back to the "I" or 9th character.
You can use a regex pattern to get the required part.
See regex example + explanation:
https://regex101.com/r/xNoBVD/2
I use positive lookbehind to force regex to get the first 3 characters at the very beginning of the line (^) without capturing it. The following 12 characters are captured and can then be replaced with ''
$regexReplacePattern = '(?<=^.{3}).{12}'
'999_987654_837I.74161.test' -replace $regexReplacePattern, ''
Hopefully this question isn't already answered on the site. I want to replace every number in a string with that number and a space. So here's what I have right now:
"31222829" -replace ("[0-9]","$0 ")
The [0-9] looks for any numbers, and replaces it with that character and the space. However, it doesn't work. I saw from another website to use $0 but I'm not sure what it means.The output I was looking for was
3 1 2 2 2 8 2 9
But it just gives me a blank line. Any suggestions?
LardPies
This probably isn't the right way to do it, but it works.
("31222829").GetEnumerator() -join " "
The .GetEnumerator method iterates over each character in the string
The -join operator will then join all of those characters with the " " space
tl;dr
PS> "31222829" -replace '[0-9]', '$& '
3 1 2 2 2 8 2 9
Note that the output string has a trailing space, given that each digit in the input ([0-9]) is replaced by itself ($&) followed by a space.
As for what you tried:
"31222829" -replace ("[0-9]","$0 ")
While enclosing the two RHS operands in (...) doesn't impede functionality, it's not really helpful to conceive of them as an array - just enumerate them with ,, don't enclose them in (...).
Generally, use '...' rather than "..." for the RHS operands (the regex to match and the replacement operand), so as to prevent confusion between PowerShell's string expansion (interpolation) and what the -replace operator ultimately sees.
Case in point: Due to use of "..." in the replacement operand, PowerShell's string interpolation would actually expand $0 as a variable up front, which in the absence of a variable expands to the empty string - that is why you ultimately saw a blank string.
Even if you had used '...', however, $0 has no special meaning in the replacement operand; instead, you must use $& to represent the matched string, as explained in this answer.
To unconditionally separate ALL characters with spaces:
Drew's helpful answer definitely works.
Here's a more PowerShell-idiomatic alternative:
PS> [char[]] '31222829' -join ' '
3 1 2 2 2 8 2 9
Casting a string to [char[]] returns its characters as an array, which -join then joins with a space as the separator.
Note: Since -join only places the specified separator (' ') between elements, the resulting string does not have a trailing space.
You can use a regex with positive lookahead to avoid the trailing space. Lookahead and lookbehind are zero-length assertions similar to ^ and $ that match the start/end of a line. The regex \d(?=.) will match a digit when followed by another character.
PS> '123' -replace '\d(?=.)', '$0 '
1 2 3
To verify there's no trailing space:
PS> "[$('123' -replace '\d(?=.)', '$0 ')]"
[1 2 3]
I have a .properties file in which I want to replace the string Compass with BBB. My question is : I want to extract string which is belong
name , JDBC/ , ds_name = '' , java.lang.String then I will update with a new one. BTW, data source name is not fixed its dynamic variable. Just I have written it as sample string.
I have tried the following PowerShell code:
$DName = read-host -prompt "Please Enter Database Name"
ForEach ($client in (Get-Content Clients.txt)) {
(Get-Content "\\$client\D$\Runtime\run.properties") -replace "$old database name which is extract","$DName" |
Out-File "\\$client\D$\Runtime\run.properties"
}
run.properties:
dsid = AdminTask.createDatasource(provider_id, '[-name Compass -jndiName jdbc/Compass
-dataStoreHelperClassName com.ibm.websphere.rsadapter.MicrosoftSQLServerDataStoreHelper
-componentManagedAuthenticationAlias TEMP-HRZEMM01Node01/PlatformDataSource -containerManagedPersistence true
-xaRecoveryAuthAlias TEMP-HRZEMM01Node01/PlatformDataSource -configureResourceProperties [[databaseName java.lang.String Compass] [portNumber java.lang.Integer 1433] [serverName java.lang.String SQLSVR1]]]')
AdminConfig.create('MappingModule', dsid , '[[authDataAlias TEMP-HRZEMM01Node01/PlatformDataSource] [mappingConfigAlias ""]]')
ds_name = 'Compass' #Name copied from your question, update if required
If I understand the question correctly, you would like to first find the database name (which can be anything, Compass is just an example) stored in the .properties file and if found replace that by a value entered in the console.
In that case, I think this should do it:
$newDbName = Read-Host -prompt "Please Enter Database Name"
$clientFile = "Clients.txt"
ForEach ($client in (Get-Content $clientFile)) {
$content = Get-Content "\\$client\D$\Runtime\run.properties" -Raw
# see if we can extract the database name from the file
if ($content -match '(?:-name\s+|jdbc/|databaseName java\.lang\.String\s+|ds_name = '')(?<dbname>[^\s''\]]+)') {
$oldDbName = $matches['dbname']
Write-Host "Replacing '$oldDbName' with '$newDbName' for client '$client'"
($content -replace $oldDbName, $newDbName) |
Out-File "\\$client\D$\Runtime\run.properties"
}
else {
Write-Warning "Could not parse the old database name from '\\$client\D$\Runtime\run.properties'.."
}
}
Regex explanation
(?: Match the regular expression below
Match either the regular expression below (attempting the next alternative only if this one fails)
-name Match the characters “-name” 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)
| Or match regular expression number 2 below (attempting the next alternative only if this one fails)
jdbc/ Match the characters “jdbc/” literally
| Or match regular expression number 3 below (attempting the next alternative only if this one fails)
databaseName\ java Match the characters “databaseName java” literally
\. Match the character “.” literally
lang Match the characters “lang” literally
\. Match the character “.” literally
String Match the characters “String” 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)
| Or match regular expression number 4 below (the entire group fails if this one fails to match)
ds_name\ =\ ' Match the characters “ds_name = '” literally
)
(?<dbname> Match the regular expression below and capture its match into backreference with name “dbname”
[^\s'\]] Match a single character NOT present in the list below
A whitespace character (spaces, tabs, line breaks, etc.)
The character “'”
A ] character
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
I am having an issue with my PowerShell Program counting the number of sentences in a file I am using. I am using the following code:
foreach ($Sentence in (Get-Content file))
{
$i = $Sentence.Split("?")
$n = $Sentence.Split(".")
$Sentences += $i.Length
$Sentences += $n.Length
}
The total number of sentences I should get is 61 but I am getting 71, could someone please help me out with this? I have Sentences set to zero as well.
Thanks
foreach ($Sentence in (Get-Content file))
{
$i = $Sentence.Split("[?\.]")
$Sentences = $i.Length
}
I edited your code a bit.
The . that you were using needs to be escaped, otherwise Powershell recognises it as a Regex dotall expression, which means "any character"
So you should split the string on "[?\.]" or similar.
When counting sentences, what you are looking for is where each sentence ends. Splitting, though, returns a collection of sentence fragments around those end characters, with the ends themselves represented by the gap between elements. Therefore, the number of sentences will equal the number of gaps, which is one less the number of fragments in the split result.
Of course, as Keith Hill pointed out in a comment above, the actual splitting is unnecessary when you can count the ends directly.
foreach( $Sentence in (Get-Content test.txt) ) {
# Split at every occurrence of '.' and '?', and count the gaps.
$Split = $Sentence.Split( '.?' )
$SplitSentences += $Split.Count - 1
# Count every occurrence of '.' and '?'.
$Ends = [char[]]$Sentence -match '[.?]'
$CountedSentences += $Ends.Count
}
Contents of test.txt file:
Is this a sentence? This is a
sentence. Is this a sentence?
This is a sentence. Is this a
very long sentence that spans
multiple lines?
Also, to clarify on the remarks to Vasili's answer: the PowerShell -split operator interprets a string as a regular expression by default, while the .NET Split method only works with literal string values.
For example:
'Unclosed [bracket?' -split '[?]' will treat [?] as a regular expression character class and match the ? character, returning the two strings 'Unclosed [bracket' and ''
'Unclosed [bracket?'.Split( '[?]' ) will call the Split(char[]) overload and match each [, ?, and ] character, returning the three strings 'Unclosed ', 'bracket', and ''