【问题标题】:Is there a way to create objects from a semi-structured text file using PowerShell?有没有办法使用 PowerShell 从半结构化文本文件创建对象?
【发布时间】:2021-06-26 21:05:33
【问题描述】:

我有以下文本文件。我正在尝试从此文件创建 PowerShell 对象。

Item: Car
In Stock: YES
Make: Ford
Model: Taurus
Color: Blue
Miles: 0
Item: Car
Miles: 0
Item: Truck
Item: SUV
Item: Car
In Stock: YES
Make: Honda
Model: Civic
Color: Red
Miles: 0

“Item”属性是每个对象开始的地方。棘手的部分是我需要每个对象都具有相同的属性。如果文本文件中不存在该属性,则获取值“N/A”。我还需要创建一个 'Found:' 属性来插入。

例如,这是我在转换为 PowerShell 对象后尝试获得的输出。

Item: Car
Found: YES
In Stock: YES
Make: Ford
Model: Taurus
Color: Blue
Miles: 0

Item: Car
Found: NO
In Stock: N/A
Make: N/A
Model: N/A
Color: N/A
Miles: 0

Item: Truck
Found: NO
In Stock: N/A
Make: N/A
Model: N/A
Color: N/A
Miles: N/A

Item: SUV
Found: NO
In Stock: N/A
Make: N/A
Model: N/A
Color: N/A
Miles: N/A

Item: Car
Found: YES
In Stock: YES
Make: Honda
Model: Civic
Color: Red
Miles: 0

您可能会想,“这输出太荒谬了。”是的,是的。我只是想用我得到的东西工作。 :)

关于尝试的解决方案..

所以,我一直在尝试做的是插入这些属性和值(如果它们不存在)。

我首先将文件读入一个列表,然后循环遍历该列表。然后,如果该元素与“Item:”匹配,则检查下一个元素。如果它不匹配“里程:”,则开始插入所需的属性。

[System.Collections.Generic.List[System.Object]]$Content = Get-Content file.txt

for ([int]$i = 0; $i -lt $Content.Count; $i++){
    if ($Content[$i] -like "Item:*"){
        if ($Content[$i+1] -like "Miles:*") {
            $Content.Insert($i+1, "Found: NO")
            $Content.Insert($i+2, "In Stock: N/A")
            $Content.Insert($i+3, "Make: N/A")
            $Content.Insert($i+4, "Model: N/A")
            $Content.Insert($i+5, "Color: N/A")
            $Content.Insert($i+6, "Miles: N/A")
        }
    }
}

这种方法似乎可以得到正确的列表结构。虽然,我担心我可能对插入物做出过多的假设。从这里开始,我仍然无法将 PowerShell 对象作为输出。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    尝试以下方法(需要 PowerShell (Core) 7+):

    # Define a custom class with the desired properties and default values.
    class Custom {
      [string] $Item = ''
      [string] $Found = 'NO'
      [string] ${In Stock}  = 'N/A'
      [string] $Make = 'N/A'
      [string] $Model = 'N/A'
      [string] $Color = 'N/A'
      [int] $Miles = 0
    }
    
    # * Split the file into paragraphs that start with an "Item:" line.
    # * Convert each paragraph into a hashtable of key-value pairs
    #   with ConvertFrom-StringData.
    # * Construct an instance of the custom class from each hashtable.
    # * Set the value of the .Found property based on which properties
    #   were populated.
    (Get-Content -Raw file.txt) -split '(?m)(?=^Item:)' -ne '' |
      ConvertFrom-StringData -Delimiter : |
        ForEach-Object {
          $obj = [Custom] $_; if ($obj.Make -ne 'N/A') { $obj.Found = 'YES' }; $obj 
        }
    

    在 Windows PowerShell 5.1 中,ConvertFrom-StringData 没有 -Delimiter 参数,因此需要进行额外的工作:向Theo 致敬。

    # Define a custom class with the desired properties and default values.
    class Custom {
      [string] $Item = ''
      [string] $Found = 'NO'
      [string] ${In Stock}  = 'N/A'
      [string] $Make = 'N/A'
      [string] $Model = 'N/A'
      [string] $Color = 'N/A'
      [int] $Miles = 0
    }
    
    # * Split the file into paragraphs that start with an "Item:" line.
    # * Convert each paragraph into a hashtable of key-value pairs
    #   with ConvertFrom-StringData.
    # * Construct an instance of the custom class from each hashtable.
    # * Set the value of the .Found property based on which properties
    #   were populated.
    (Get-Content -Raw file.txt) -split '(?m)(?=^Item:)' -ne '' -replace '(?m)^(.+?):', '$1=' |
      ConvertFrom-StringData |
        ForEach-Object {
          $obj = [Custom] $_; if ($obj.Make -ne 'N/A') { $obj.Found = 'YES' }; $obj 
        }
    

    【讨论】:

    • @mklement0 感谢您的帮助。这正是我一直在寻找的并解决了我发布的问题。我现在正在解决其他一些问题。我可能需要发布一个新问题。
    • 很高兴听到答案有帮助,@okkv1747vm。
    猜你喜欢
    • 2020-02-05
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多