0

I am trying to search a specific string at a specific position in a text file and replace it with some other text. the texts are separated by the pipe character. So I know I have to replace the text which appears after the 6th pipe character. but I am unable to formulate the regular expression. Please help please is the example of my entire search string in a file

MACADD||TEST|Street1|CITY||Taiwan|||10000000|||FIRE||Taiwan||||||||12 days||30 Days|DDTE||812148709231890||124-Taiwan|DENE|||



$Files = Get-content -Path F:\Newfolder\*.csv




 $CountryCodeLookup = @{
    'USA'= 'United States'
    'Taiwan' = "Taiwan, Republic of China" # for this item csv file become strange
    }

foreach ($File in $Files)
    {
    $DelimCount = ($File -replace '[^|]', '').Length
    $CSV_Thing = ConvertFrom-Csv -Delimiter '|' -InputObject $File -Header @(1..$DelimCount)

    If ($CountryCodeLookup.ContainsKey($CSV_Thing.7))    
    {
    $CSV_Thing.7 = $CountryCodeLookup[$CSV_Thing.7]
    }


    $OutString = (($CSV_Thing |
        ConvertTo-Csv -Delimiter '|' -NoTypeInformation |
        Select-Object -Skip 1) -replace '"', '') + '|' | Set-Content $File.PSPath -Force

    }
Nishant
  • 7
  • 3
  • 1
    the most obvious - to me - is to just replace the string. perhaps with pipes on each end, but just do a direct replacement. if you need a bit more flexible method, the line can be treated as a CSV row with the pipes as delimiters. read it in with `Import-CSV` or convert it with `ConvertFrom-CSV`, make your changes, and then rewrite it. – Lee_Dailey May 18 '20 at 13:30
  • Actually I do not want to replace all the occurrences of my find string because that's another issue. – Nishant May 18 '20 at 13:40
  • Does the text file have headers? – Mathias R. Jessen May 18 '20 at 13:40
  • I found an expression but I do not know how to use it my way: -replace "(?<=^((\|[^|]*){5})+)\|","`n|" this expression also searches for the pipe character and replaces the 6th pipe with the next line starting with a pipe character. I need a similar expression. No, the text file does not have any header – Nishant May 18 '20 at 13:46
  • @Nishant - please see the Answer i just posted. it demos treating the string as a one-line CSV to get to the column you want to work on. – Lee_Dailey May 18 '20 at 14:12

1 Answers1

1

here is a demo of what i meant by using the CSV cmdlets to get to the item after the 6th delimiter.

what it does ...

  • creates a list of strings to work with
    when ready to do this for real, remove the entire #region/#endregion block and use Get-Content.
  • creates a lookup table for the 2-letter country codes to full country names
  • iterates thru the collection of sample strings
  • replaces all the non-pipe chars with nothing
  • counts the remaining chars
  • converts the string to an object using the pipe as a delimiter and the count of delimiters as the column headers
  • checks to see if the look up table contains the item in column 7
  • if YES, replaces the value in the property named 7 with the value looked up from the $CountryCodeLookup hashtable
  • if NO, leave the item value as is
  • converts the object to a CSV
  • skips the 1st line
    that holds the unwanted header line.
  • removes the unwanted double quotes
  • adds the missing trailing single pipe
    that was caused by the way that the empty object didn't show up in the new CSV string.
  • displays the original string and the new version

the code ...

#region >>> fake reading in a file of plain text lines
#    in real life, use Get-Content
$InStuff = @'
MACADD||TEST|Street1|CITY||USA|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||UK|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||DE|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||RU|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||ZIGZAG|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
'@ -split [System.Environment]::NewLine
#endregion >>> fake reading in a file of plain text lines

$CountryCodeLookup = @{
    USA = 'United States'
    UK = 'United Kingdom'
    DE = 'Germany'
    RU = 'Russian Federation'
    }

foreach ($IS_Item in $InStuff)
    {
    $DelimCount = ($IS_Item -replace '[^|]', '').Length
    $CSV_Thing = ConvertFrom-Csv -Delimiter '|' -InputObject $IS_Item -Header @(1..$DelimCount)
    # deal with items that are not in the lookup table
    #    if the item is in the key list, do the lookup & assign the matching value
    #    else leave it unchanged
    if ($CountryCodeLookup.ContainsKey($CSV_Thing.7))
        {
        $CSV_Thing.7 = $CountryCodeLookup[$CSV_Thing.7]
        }

    $OutString = (($CSV_Thing |
        ConvertTo-Csv -Delimiter '|' -NoTypeInformation |
        # get rid of the unwanted double quote and add the missing trailing pipe
        Select-Object -Skip 1) -replace '"', '') + '|'

    $IS_Item
    $OutString
    '=' * 30
    }

output ...

MACADD||TEST|Street1|CITY||USA|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||United States|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
==============================
MACADD||TEST|Street1|CITY||UK|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||United Kingdom|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
==============================
MACADD||TEST|Street1|CITY||DE|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||Germany|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
==============================
MACADD||TEST|Street1|CITY||RU|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||Russian Federation|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
==============================
MACADD||TEST|Street1|CITY||ZIGZAG|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
MACADD||TEST|Street1|CITY||ZIGZAG|||10000000|||FIRE||0||||||||12 days||30 Days|DDTE||812148709231890||124-USA|DENE|||
==============================

that seems to do what your current version of the problem requires. [grin]

Lee_Dailey
  • 7,292
  • 2
  • 22
  • 26
  • Hi Lee, appreciate your efforts, actually, I need to read multiple such text files and replace the exact text at the exact location in the files. and every file will have different contents but in a similar format. in some file I need to change USA to United States, in some files I need to replace SA to South Africa. I suppose you got my idea – Nishant May 18 '20 at 14:42
  • the code i showed will do that. it replaces the nth item with the indicated value. that is what you described in your title ... has that changed? – Lee_Dailey May 18 '20 at 14:46
  • By replacing, I meant to Find and replace. I have multiple text files where between 6th and 7th pipe characters I need to find the texts and replace them with my own text. and I need to do it with multiple text files – Nishant May 18 '20 at 14:57
  • the code posted lets you see the item at that location. it also lets you replace it if desired. the exact replacement is NOT part of what you asked ... however, it is quite easy to use a lookup table to replace any given test with the preferred replacement. $CountryNameLookup[$CSV_Thing.7]` will let you find the key-value pair and use that value for your replacement. – Lee_Dailey May 18 '20 at 15:13
  • I have added my code in the above statement, please see that. – Nishant May 18 '20 at 15:37
  • you have seriously changed the requirements ... [*grin*] i will rewrite it all and show you how to use the demo i posted in your newly changed situation. – Lee_Dailey May 18 '20 at 15:59
  • @Nishant - the rewritten version is up. i think it does what your current description seems to need done. – Lee_Dailey May 18 '20 at 16:08
  • getting error Index operation failed; the array index evaluated to null. At line:19 char:5 + $CSV_Thing.7 = $CountryCodeLookup[$CSV_Thing.7] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : NullArrayIndex – Nishant May 18 '20 at 17:01
  • @Nishant - did you test the code _exactly as it is posted_ - with no changes? – Lee_Dailey May 18 '20 at 17:37
  • Please ignore the previous error. that is sorted. Now I am kind of running into another problem.. the hashtable you showed me it has simple left-hand values but I have values to put in which has special characters like (),'. in them. how to define them? – Nishant May 18 '20 at 17:44
  • the key must be unique and should be something that is NOT used by powershell for other things. are you really needing to use `()` parentheses in the key? if so, try enclosing the key in single quotes like `'Yes(No)Maybe'`. – Lee_Dailey May 18 '20 at 17:49
  • Thanks Lee, this really helped me. :) thank you for your support – Nishant May 18 '20 at 18:00
  • I have an observation for your code.. it seems like whenever the code finds a match from the hash table it is replacing it correctly but when no match found it is deleting the existing value. I do not want this. how to avoid such deletion – Nishant May 18 '20 at 18:19
  • @Nishant - oops! [*blush*] i should have thot of that ... let me tinker with it - i will let you know when i get that fixed. – Lee_Dailey May 18 '20 at 20:47
  • @Nishant - take a look at the new version. i added a check for "is it in the lookup table?". if YES, use the lookup value. if NO, leave it as it is. – Lee_Dailey May 18 '20 at 20:59
  • Hi @Lee_Dailey, I have a query. can you please help me with this. your code actually works fine, and I tried the same code on CSV files and it worked though but when there is a comma in the replacement string then entire data gets separated into as many columns as many commas are there in the replacement string. I have modified my top code, please have a look. Thanks – Nishant May 27 '20 at 14:19
  • @Nishant - please, make a new Question on that & include sample data that triggers the problem, AND show the problem in the output data. things have changed so much & so often that i cannot recall what the details are. [*blush*] – Lee_Dailey May 27 '20 at 17:01
  • Hi @Lee_Dailey, I have raised a new question at below link, please see https://stackoverflow.com/questions/62045851/how-to-find-replace-a-string-appearing-at-nth-position-in-a-pipe-delimited-csv – Nishant May 27 '20 at 17:20