1

I have a (hopefully) quick question that I can't seem to work out on my own.

I have a string:

ITEM1 Quantity: 12x 355ml bottlePrice: $23.95 $23.50 SAVE $0.45

That I would like to split out and insert into a CSV file. The columns in the generated CSV, and their values, would be:

Name: (everything before "Quantity:" in the above string.)

Quantity: (between Quantity and x)

Size: (Everything between x and bottle)

OrigPrice: (Everything after Price and the second $ sign)

SalePrice: (Everything between OrigPrice and SAVE)

Savings: (Everything after "SAVE")

I hope this all makes sense, I can provide more info if needed.

I appreciate the help!

1 Answer 1

2

How about something like:

$subject = 'ITEM1 Quantity: 12x 355ml bottlePrice: $23.95 $23.50 SAVE $0.45'

if ($subject -cmatch '^(?<Name>.*)Quantity:(?<Quantity>.*)x(?<Size>.*)bottle\s*Price:(?<OrigPrice>.*)\s*(?<SalePrice>\$.*)SAVE(?<Savings>.*)$') {
    $result = $matches[0]
} else {
    $result = ''
}

"Matches:"
$matches

I couldn't tell if there really needed to be a space between bottle & Price (it didn't look like it, but it'll handle it if there is).

If you need the name, you can access it like:

$matches["Name"]

A better solution (and one that actually gets it to CSV format, would be something like the following (thanks to @nickptrvc for pointing out what I missed):

function Read-Data {
[cmdletbinding()]
    param(
        [parameter(Mandatory)][string]$Path
    )

    $reader = [System.IO.File]::OpenText($Path)

    while(( $subject = $reader.ReadLine()) -ne $null ) {
        if ($subject -cmatch '^(?<Name>.*)Quantity:(?<Quantity>.*)x(?<Size>.*)bottle\s*Price:(?<OrigPrice>.*)\s*(?<SalePrice>\$.*)SAVE(?<Savings>.*)$') {
            $result = $matches[0]
            $obj = [PSCustomObject]@{
                Name=$matches["Name"].trim();
                Quantity=$matches["Quantity"].trim();
                Size=$matches["Size"].trim();
                OrigPrice=$matches["OrigPrice"].Trim();
                SalePrice=$matches["SalePrice"].Trim();
                Savings=$matches["Savings"].Trim()
            }
            $obj
        }
    }
}

Then, to use it, save this to a file (I called mine Read-Data.ps1), source the file, and then you have two options: 1) you can use ConvertTo-Csv to simply convert the objects to CSV, and return the result to the screen, or you can use Export-Csv to save it to a file:

. C:\Test\Convert-Data.ps1
Read-Data -Path C:\Test\datafile.dat | ConvertTo-Csv -NoTypeInformation

or

Read-Data -Path C:\Test\datafile.dat | Export-Csv -NoTypeInformation -Path C:\Test\datafile.csv
Sign up to request clarification or add additional context in comments.

5 Comments

To get the CSV result, you can add this in true scope of the if block. The order will be alphabetical by the key names, which are the regex group names in this case e.g. Name, Quantity, etc... if (...) { $matches.remove(0) $result = ($matches.values | %{$_.trim()}) -join ', ' } else { ... }
Thanks @nickptrvc, kinda got so impressed w/ the regex that I forgot to answer the rest of the question... :) I updated my answer w/ a function that returns an object suitable for Export-Csv and ConvertTo-Csv...
I too was impressed by the regex! I will say that I suggested the snippet because it doesn't require the user to have to type the key names like $matches['Size'] making it somewhat more dynamic (constraint by the regex of course). I definitely liked the PSCustomObject type idea, but the user must be using version 3 in order to create these types. In version 2, using PSObject is really slow. So in this case I usually default to just using a hash table and concatenating the strings. Biggest advantage is the backwards compatibility from 3 to 2.
Good point, @nickptrvc, I didn't even think of the performance hit on v1/v2... I've been smacked around enough for wondering if someone is running anything earlier than v3, that I've just started assuming, which is probably not the best plan... :)
Wow, this is an amazing answer. It got the job done elegantly and its easy to follow. I also love the regex! Thanks so much for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.