Search for a value in an array of PSCustomObjects

I have the following (abstract) of code:

$products = "product,description,qty`nabc123,""Product 123"",1`nxyz826,""Product 826"",0`nabc483,""Product 483"",12" | ConvertFrom-Csv -Delimiter ","
$products.GetType()
IsPublic IsSerial Name               BaseType
True     True     Object[]           System.Array
$products[0].GetType()
IsPublic IsSerial Name               BaseType
True     False    PSCustomObject     System.Object

$products
product description qty
------- ----------- ---
abc123  Product 123 1  
xyz826  Product 826 0  
abc483  Product 483 12

I’d like to find every string which contains a particular value (e.g. “8”) irrespective of where it is. For example:

$products | searchfor "8"
xyz826
Product 826
abc483
Product 483

Is there a performant way to do this? I’ve been investigating [Linq.Enumerable]::Where() but keep hitting the error “Index operation failed; the array index evaluated to null.” even when I’m just trying examples from the web.

[Linq.Enumerable]::Range(0, $products.Count).Where({param($i) $products[$i] -match "8"})
Index operation failed; the array index evaluated to null.
At line:1 char:63
+ ... Range(0, $products.Count).Where({param($i) $products[$i] -match "8"})
+                                                ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex
 
Index operation failed; the array index evaluated to null.
At line:1 char:63
+ ... Range(0, $products.Count).Where({param($i) $products[$i] -match "8"})
+                                                ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex
 
Index operation failed; the array index evaluated to null.
At line:1 char:63
+ ... Range(0, $products.Count).Where({param($i) $products[$i] -match "8"})
+                                                ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

This code is just a way to demonstrate the problem I’m trying to solve which is why it’s a little odd.

Thanks.

Depending on what the actual purpose of that requirement is … how about using Select-String on the plain CSV text of the data?

BTW: Creating CSV reads much easier this way:

$products = 
@'
product,description,qty
abc123,"Product 123",1  
xyz826,"Product 826",0  
abc483,"Product 483",12
'@ | 
    ConvertFrom-Csv

Hi. Thanks or the formatting suggestion. I just copied it from my test scenario but you’re right that it is easier to read in a forum when it is formatted sensibly :slight_smile:

I agree with the “Select-String” suggestion but this is part of a wider problem I’m trying to solve:

  • CSV file with embedded LF within the text and LF as the end of line
  • Replace the embedded LF but not the end of line

Using ConvertFrom-Csv, it splits at the the end of line characters (into an object array of PSCustomObjects) but retains the embedded LF characters. If I can then track down the values (e.g. description in one row) that contain these embedded LF characters, I can escape them. Using only regex, I have to be sure that the LF character I’m finding is genuinely embedded and not an end of line.

Thanks again.

How about this:

And what’s the issue with that?

Edit:

How many columns does your input CSV have actually?

Hi again. Yeah I’ve been looking at a regex pattern and it’s close but the ConvertFrom-Csv was handling a lot of embedded quotes in the data, etc. and I was hoping this could be a shortcut to a solution. There are 299 columns in the input file!

At the moment, my regex is:

[string]$raw = Get-Content -Path $filename -Raw
[string]$escaped = $raw -replace "([`n|])(""[^""]*)`n([^""]*"")([|`n])", '$1$2<--EOL-->$3$4' -replace "([`n|])(""[^""]*""""[^""]*)`n([^""]*"")([|`n])", '$1$2<--EOL-->$3$4'

which is sending me crazy :smiley:

For those who don’t speak regex fluently:

1st “-replace”


with the result being:

1st Captured Group
2nd Captured Group
<–EOL–>
3rd Captured Group
4th Captured Group

2nd “-replace” (to handle escaped double-quotes within a value)


with the result being:

1st Captured Group
2nd Captured Group
<–EOL–>
3rd Captured Group
4th Captured Group

Hmm … does it have to be that complex? Depending on how your input data really look like and if every single cell is wrapped in double quotes I’d start with a simple negative lookahead. I mentioned that before. I’d look for a line break character NOT followed by a double quote.

[string]$raw = Get-Content -Path $filename -Raw
[string]$escaped = $raw -replace '`n(?!")'

… I’m not sure if the double quotes needs to be escaped … in this case you could try …

[string]$raw = Get-Content -Path $filename -Raw
[string]$escaped = $raw -replace '`n(?!\")'

The script is going to be processing differently-formatted files and all I can rely on is:

  • any field containing embedded LF characters will be will be contained within double-quotes
  • the delimiter will be known in advance
  • any double-quotes within a field will be:
    – contained within a quoted field
    – represented as two double-quote characters

Based on this, I think the regex is as simple as it can be.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.