Regex in Powershell, line by line from txt-file?

Welcome Forums General PowerShell Q&A Regex in Powershell, line by line from txt-file?

Viewing 20 reply threads
  • Author
    Posts
    • #265664
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      I do have a text-file named ord.txt that looks like this:

      Anna:Annamaria
      Sugar:Agave
      Android:Phone

      I want to import line by line from the ord.txt and replace the first word with the second word (Anna will be replaced with Annamaria, but not Annasofia should not be Annamariasofia) and so on in another selected file $FileBrowser.FileName. But I can not figure out how to import line by line to get it to replace every first word to the second word from the ord.txt. Is this possible or is there other solutions that is possible to do in PowerShell?

      All the first words in every line in ord.txt are the once that needs to be replaced in the other file selected. There will be about 300 words in the ord.txt file.

      $editButton.Add_Click({ ((Get-Content $FileBrowser.FileName -Raw) -replace $ScriptDir\ord.txt -First 1, $ScriptDir\ord.txt -First 2) | Set-Content $FileBrowser.FileName })

    • #265685
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      I’m not entirely sure I’ve understood what you’re trying to do, but isn’t it just a case of removing everything up to and including the ‘:’

       

       

      • This reply was modified 1 month ago by Matt Bloomfield. Reason: Code formatting
    • #265691
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      (Get-Content E:\Temp\ord.txt) -replace ‘^.+:’,” | Out-File E:\Temp\ord2.txt

      I think that I was a bit unclear on what I want. The file “ord.txt” is not the file that should be edited, its the other file “$FileBrowser.FileName” (that is selected by a button).

      For Example, in the $FileBrowser.FileName, I have a text like this:

      Anna is a person that is friends with Annasofia and loves Sugar.

      I want the words replaced by the list from the “ord.txt”, like this:

      Annamaria is a person that is friends with Annasofia and loves Agave.

      So I want in the line “Anna:Annamaria”, that Anna is replaced by Annamaria, and Sugar:Agave, “Sugar” is replaced with “Agave”.

      I have tried another way to somewhat get it to work, but I cant figure it out, it should go thrugh every like and replace every word in the list in “ord.txt”

      $Content = Get-Content -encoding utf8 &#039;<span class="&quot;crayon-v&quot;">$ScriptDir</span><span class="&quot;crayon-sy&quot;">\</span>ord.txt&#039;
      ((Get-Content $<span class="&quot;crayon-v&quot;">FileBrowser</span><span class="&quot;crayon-sy&quot;">.</span><span class="&quot;crayon-i&quot;">FileName&quot;</span> -Raw) -replace &#039;$Content[1]&#039;, &#039;$Content[1]&#039;) | Set-Content $FileHtmlBrowser.FileName

      But I can not figure out how to use first word before the “:” with $Content[1], and the other that is suppose to replace with the one after the “:”.

      • This reply was modified 1 month ago by Cal Alendo. Reason: was some wrong
    • #265697
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      I also found that I can get the first word with this from ord.txt:

      foreach ($line in $lines[1]){ Write-Host ($line.Split(":"))[0] }

      and the other word with this from ord.txt:

      foreach ($line in $lines[1]){ Write-Host ($line.Split(":"))[1] }

      But I want it to go thrugh every $lines[ ] and do the same.

      In that case its just  ($line.Split(“:”))[0] and ($line.Split(“:”))[1], that I need in the script, but I can not figure out how to make it change the $lines number so It go through every line, not only the first one.

    • #265700
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      It looks like my first answer dissapeared somehow, but here it is:

      (Get-Content E:\Temp\ord.txt) -replace ‘^.+:’,” | Out-File E:\Temp\ord2.txt

      I think that I was a bit unclear on what I want. The file “ord.txt” is not the file that should be edited, its the other file “$FileBrowser.FileName” (that is selected by a button).

      For Example, in the $FileBrowser.FileName, I have a text like this:

      Anna is a person that is friends with Annasofia and loves Sugar.

      I want the words replaced by the list from the “ord.txt”, like this:

      Annamaria is a person that is friends with Annasofia and loves Agave.

      So I want in the line “Anna:Annamaria”, that Anna is replaced by Annamaria, and Sugar:Agave, “Sugar” is replaced with “Agave”.

      I have tried another way to somewhat get it to work, but I cant figure it out, it should go thrugh every like and replace every word in the list in “ord.txt”

      $Content = Get-Content -encoding utf8 &#039;$ScriptDir\ord.txt&#039;
      ((Get-Content $FileBrowser.FileName&quot; -Raw) -replace &#039;$Content[1]&#039;, &#039;$Content[1]&#039;) | Set-Content $FileHtmlBrowser.FileName

      But I can not figure out how to use first word before the “:” with $Content[1], and the other that is suppose to replace with the one after the “:”.

    • #265706
      Participant
      Topics: 8
      Replies: 670
      Points: 2,640
      Helping Hand
      Rank: Community Hero

      Since the words can land anywhere in the line, you need to figure out what the differentiating criteria will be. It seems to me that could be as long as the word to be replaced is followed by anything but another letter. For that you can use a lookahead. Either a positive lookahead to match the word as long as it’s not followed by a letter, or a negative look ahead that matches unless it’s followed by a letter. An example of each.

      Positive lookahead where the next character is \W (capital W meaning not a word character)

      Negative lookahead where the next character is not \w (lowercase w meaning a word character)

      Now you just need to figure out how to apply each replacement pair to each line (if I understood you correctly.) Since you are applying the replacements to every line, you can do so all at once.. since the criteria is a whole word followed by anything but a word character. I think it would be easiest to use Get-Content -Raw Once you have the text you can loop through each pair in the orb updating the text each time. The following example should help clarify what I mean.

      And now $text contains the updated text which you can write back to a file or continue doing whatever you needed to.

    • #265712
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      I would treat orb like a dictionary and create a hash table (which is PowerShell parlance for a dictionary) from the file.  You can then loop over every key in the hash table and replace each occurance of the word:

       

    • #265778
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      Thank you for all the answers.

      Doug Maurer so for getting the script Case sensitive I have a problem, I thought I had it figured out (?=\Wi), but that does change words like “anna” to “Annamaria”. I also tried a few other ways that worked in regex101, but none worked in PowerShell. I can not figure it out. I tried all day yesterday, or regex might work different in powershell?

      Anna anna gives: Annamaria Annamaria but it should be: Annamaria anna

      Matt Blomfield, I do like this as well, this might be what I will be using. But I get the same problem here as above with the words. “\b$key\b” it does change Anna and anna to Annamaria, but only Anna should be changed. Wierdly in regex101 it does mark Anna and not anna.

      I was thinking about upper and lower case as well, is it possible to do something like this to if all words are lowercase in the ord-file, so It matches first by all lower case and then with the first letter as uppercase if its the first of a sentence or is a name?
      (($text.Text.Substring(0,1)).toupper()+($text.Text.Substring(1,($text.Text.length -1)).ToLower())

       

    • #265805
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      The -replace operator is not case sensitive by default but you can use -creplace to make it so.  Just make sure the word uses the correct case in your dictionary.

       

       

    • #265814
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      Thank you Matt Bloomfield that solved everything, I have made some small editing. I did also redo the “dictionary” so it has lowercase and also first letter as uppercase.

      I never heard of -creplace, so wierd, I read about -replace and didn’t come across it, not mentioned once. (That did also solved another problem I had in another project to learn powershell)

      Big thanks! 

    • #265817
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      This is true for all the comparison operators, see Get-Help about_comparison_operators

      Althought it’s the default, you can also explicitly use case insensitive operators for example -ireplace -ilike -icontains

    • #266405
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      That gives me a lot more options!

       

    • #266408
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      A related question, is it possible to get a progressbar to work with the script? I don’t get how the progressbar work. I did follow a tutorial on how to set a timer but I can not figure out how it worked.

       

      $editButton_Click = {
      $progressbar1 = Get-Content $Path\ord.txt -encoding utf8 | foreach {
      $find, $replace = $_ -split ':'
      ((Get-Content $FileBrowser.FileName -Raw) -creplace "$find(?=\W)", $replace) | Set-Content $FileBrowser.FileName -encoding utf8
      }}

    • #266531
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      It’s pretty straightforward with Write-Progress.   Using my example above, this would be inserted at line 14:

      For Doug’s version, or the code you’ve posted, you would need to change it slightly to make it easier to get the length of the file.

       


    • #267017
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      The “Write-Progress” is great to get it to publish in the powershell windows.

      But I want the $progressbar1 in the GUI to change and when all words are complete it will be 100%

    • #267032
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      Sorry, that wasn’t clear from the code you posted.  Can you share the GUI code?

    • #267047
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      I was unclear on that part, sorry for that. I have created a powerbar in the GUI and it is called $progressbar1. Most tutorials and examples are often when transfering files and by “.count”

      $editButton_Click = {
      Get-Content $Path\ord.xml -encoding utf8 | foreach {
      $find, $replace = $_ -split ':'
      ((Get-Content $FileBrowser.FileName -Raw) -creplace "$find(?=\W)", $replace) | Set-Content $FileBrowser.FileName -encoding utf8
      }
      $oReturn = [System.Windows.Forms.Messagebox]::Show("Done")
      }

      I have somewhat got it to work, but this opens a new windows, but I want the progressbar in the GUI to change, not open in a new window.

      $richtextbox1.AppendText((Write-Progress -Activity "Changing " -CurrentOperation "$($find) with $($replace)" -Status "Processing $($ord.IndexOf($_) + 1) of $($ord.Length)"));

    • #267683
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      The progress bar was quite a difficult problem to solve.  The problem being the GUI and the loop run in the same thread so if you launch the GUI before the loop, the loop doesn’t run until you close the form, and if you launch the GUI after the loop, the progress bar is already at 100%.

      Following a couple of tutorials linked below, the script below adds a progress bar to a form.

      First time working with progress bars on forms so I’m open to suggestions on how to improve this.

      Fox Deploy – Building Responsive Apps With Progess Bars

      Learn-PowerShell.net – Writing Data to a UI from a Different Runspace

       

       

       

      • This reply was modified 3 weeks, 3 days ago by Matt Bloomfield. Reason: Fixed broken link
    • #268643
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      Thank you so much! This was a bit harder for me to understand. I think I understand the script. There is a few things I have to look up and read about to understand however (mostly cause English is not my main language and many words are unknown to me)

      BTW, a last thing, is it possible to output the “Write-Progress” to a “richtextbox”? Or is it possible to “mirror” the powershell screen from the background into the richtextbox?

      Here is the script i use:

      <span class="crayon-sy">(</span><span class="crayon-sy">(</span><span class="crayon-r ">Write-Progress</span><span class="crayon-h"> </span><span class="crayon-cn">-Activity</span><span class="crayon-h"> </span><span class="crayon-s">"Changing "</span><span class="crayon-h"> </span><span class="crayon-cn">-CurrentOperation</span><span class="crayon-h"> </span><span class="crayon-s">"$($find) with $($replace)"</span><span class="crayon-h"> </span><span class="crayon-cn">-Status</span><span class="crayon-h"> </span><span class="crayon-s">"Processing $($ord.IndexOf($_) + 1) of $($ord.Length)"</span><span class="crayon-sy">)</span><span class="crayon-sy">)</span><span class="crayon-sy">;</span>

      I did try to fix by doing this:

      Function Write-Progress
      {
      Param ($Message)
      $powershellBox.AppendText()
      $powershellBox.Refresh()
      $powershellBox.ScrollToCaret()
      }

      <span class="crayon-sy">(</span><span class="crayon-sy">(</span><span class="crayon-r ">Write-Progress</span><span class="crayon-h"> </span><span class="crayon-cn">-Activity</span><span class="crayon-h"> </span><span class="crayon-s">"Changing "</span><span class="crayon-h"> </span><span class="crayon-cn">-CurrentOperation</span><span class="crayon-h"> </span><span class="crayon-s">"$($find) with $($replace)"</span><span class="crayon-h"> </span><span class="crayon-cn">-Status</span><span class="crayon-h"> </span><span class="crayon-s">"Processing $($ord.IndexOf($_) + 1) of $($ord.Length)"</span><span class="crayon-sy">)</span><span class="crayon-sy">)</span><span class="crayon-sy">;</span>

      I did also try this:

      Start-Transcript = $powershellBox.AppendText()
      Write-Progress -Activity "Replacing Words" -CurrentOperation "Ersätter $($find) med $($replace)" -Status "Processing $($ord.IndexOf($_) + 1) of $($ord.Length)"
      Stop-Transcript

      But none of them work.

    • #268703
      Participant
      Topics: 2
      Replies: 377
      Points: 496
      Helping Hand
      Rank: Contributor

      BTW, a last thing, is it possible to output the “Write-Progress” to a “richtextbox”? Or is it possible to “mirror” the powershell screen from the background into the richtextbox?

      No, it’s not.  Write-Progress doesn’t generate any output.

    • #268790
      Participant
      Topics: 2
      Replies: 12
      Points: 42
      Rank: Member

      Ah, okey. Then I will look on other options. Thank you for all help.

Viewing 20 reply threads
  • You must be logged in to reply to this topic.