Regex 读取半结构化文本文件

Regex 读取半结构化文本文件,regex,powershell,Regex,Powershell,我有一个文本文件,其中包含每个文档集的元数据和文件路径。元数据仅在集合的开头分配,但集合可能包含一个或多个文档。我需要为每个文档集创建一个CSV或XML输出(每个对象以“BEGIN:”开头),这样我就可以导入到另一个系统中 我有一个PS脚本,它正在解析文本文件中的每个对象,并为每个对象创建一个删除的字符串,但我认为这不是解析这些数据的最有效的方法。在解析此文本文件和正确设置XML/CSV输出时,有人能帮助我找到正确的方向吗 潜在问题 对象可以有一个或多个用户名 对象可以有一个或多个图像文件路径

我有一个文本文件,其中包含每个文档集的元数据和文件路径。元数据仅在集合的开头分配,但集合可能包含一个或多个文档。我需要为每个文档集创建一个CSV或XML输出(每个对象以“BEGIN:”开头),这样我就可以导入到另一个系统中

我有一个PS脚本,它正在解析文本文件中的每个对象,并为每个对象创建一个删除的字符串,但我认为这不是解析这些数据的最有效的方法。在解析此文本文件和正确设置XML/CSV输出时,有人能帮助我找到正确的方向吗

潜在问题

  • 对象可以有一个或多个用户名
  • 对象可以有一个或多个图像文件路径
  • 示例文本文件


    这对你有帮助吗

    Get-Content testfile.txt -Delimiter 'BEGIN:' |
    Select -Skip 1 |
    foreach {
    $DOC = [PSCustomObject]@{
            DocTypeName = $Null
            DocDate = $Null
            Reference = $Null
            UserName = [collections.arraylist]@()
            FileName = [collections.arraylist]@()
            }
    
    Switch -Regex ($_.split("`n"))
     {
       'DocTypeName: (.+)' {$DOC.DocTypeName = $Matches[1];Continue}
       '>>DocDate: (.+)'   {$DOC.DocDate = $Matches[1];Continue}
       'Reference #: (.+)'  {$DOC.Reference = $Matches[1];Continue}
       'User Name: (.+)'  {[void]$DOC.UserName.add($Matches[1]);Continue}
       '>>FileName: (.+)' {[void]$DOC.FileName.add($Matches[1]);Continue}
     }
    
    $DOC
    }
    

    这对你有帮助吗

    Get-Content testfile.txt -Delimiter 'BEGIN:' |
    Select -Skip 1 |
    foreach {
    $DOC = [PSCustomObject]@{
            DocTypeName = $Null
            DocDate = $Null
            Reference = $Null
            UserName = [collections.arraylist]@()
            FileName = [collections.arraylist]@()
            }
    
    Switch -Regex ($_.split("`n"))
     {
       'DocTypeName: (.+)' {$DOC.DocTypeName = $Matches[1];Continue}
       '>>DocDate: (.+)'   {$DOC.DocDate = $Matches[1];Continue}
       'Reference #: (.+)'  {$DOC.Reference = $Matches[1];Continue}
       'User Name: (.+)'  {[void]$DOC.UserName.add($Matches[1]);Continue}
       '>>FileName: (.+)' {[void]$DOC.FileName.add($Matches[1]);Continue}
     }
    
    $DOC
    }
    

    我将在“BEGIN:”上导入文件拆分(就像mjolinor一样),然后通过ForEach运行它,该ForEach将使用导入的记录中的任何属性使用Add Member构建一个对象。如果您对我的代码有任何疑问,请询问

    $RawData = Get-Content testfile.txt -Delimiter 'BEGIN:' | Select -Skip 1
    $Records = ForEach($Object in $RawData){
        $Record=New-Object PSObject
        $Object.split("`n")|Where{$_ -match "^(?:>>)?(.+?):\s*?(\S.*)?$"}|ForEach{
            If([String]::IsNullOrEmpty($Record.($Matches[1]))){
                Add-Member -InputObject $Record -NotePropertyName $Matches[1] -NotePropertyValue @($Matches[2])
            }Else{
                $Record.($Matches[1])+=$Matches[2]
            }
    
        }
        $Record
    }
    

    这就给您留下了一个数组,
    $Records
    ,其中包含具有输入文件提供的任何属性的对象。如果您只需要特定的字段,那么mjolinor的解决方案可能是一个更好的选择。

    我将在“开始:”(与mjolinor一样)上导入文件拆分,然后通过ForEach运行它,该ForEach将使用导入的记录中的任何属性构建一个具有Add Member的对象。如果您对我的代码有任何疑问,请询问

    $RawData = Get-Content testfile.txt -Delimiter 'BEGIN:' | Select -Skip 1
    $Records = ForEach($Object in $RawData){
        $Record=New-Object PSObject
        $Object.split("`n")|Where{$_ -match "^(?:>>)?(.+?):\s*?(\S.*)?$"}|ForEach{
            If([String]::IsNullOrEmpty($Record.($Matches[1]))){
                Add-Member -InputObject $Record -NotePropertyName $Matches[1] -NotePropertyValue @($Matches[2])
            }Else{
                $Record.($Matches[1])+=$Matches[2]
            }
    
        }
        $Record
    }
    

    这就给您留下了一个数组,
    $Records
    ,其中包含具有输入文件提供的任何属性的对象。如果您只需要特定字段,那么mjolinor的解决方案可能是一个更好的选择。

    仅供V5-ConvertFrom字符串中的新命令参考。这需要一个模板,您可以使用该模板告诉命令如何解释文本,例如:

    BEGIN:
    DocTypeName: SAMPLE
    >>DocDate: 12/11/2008
    Reference #: {Reference*:{Number:0001122}
    User Name: {UserNames:{UserName*:George Washington}
    User Name: {UserName*:Martha Washington}}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Paths:{Path*:[path]\761019.TIF}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Path*:[path]\761020.TIF}}}
    BEGIN:
    DocTypeName: SAMPLE
    >>DocDate: 12/11/2008
    Reference #: {Reference*:{Number:0001123}
    User Name: {UserNames:{UserName*:Abe Lincoln}}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Paths:{Path*:[path]\761021.TIF}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Path*:[path]\761022.TIF}}}
    
    然后,您可以抛出原始文件内容(在变量$content中)并访问数据,如下所示:

    $res = $content | cfs -TemplateFile .\template.txt
    PS> $res[0].Reference.Number
    0001122
    PS> $res[0].Reference.UserNames.UserName.value
    George Washington
    Martha Washington
    PS> $res[0].Reference.Paths.Path.value
    [path]\761019.TIF
    [path]\761020.TIF
    

    在预览表单中使用此命令有点笨拙,因为它希望在默认情况下显示
    Extent
    属性,我认为您只需要调试模板。

    只是V5-ConvertFrom字符串中新命令的参考。这需要一个模板,您可以使用该模板告诉命令如何解释文本,例如:

    BEGIN:
    DocTypeName: SAMPLE
    >>DocDate: 12/11/2008
    Reference #: {Reference*:{Number:0001122}
    User Name: {UserNames:{UserName*:George Washington}
    User Name: {UserName*:Martha Washington}}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Paths:{Path*:[path]\761019.TIF}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Path*:[path]\761020.TIF}}}
    BEGIN:
    DocTypeName: SAMPLE
    >>DocDate: 12/11/2008
    Reference #: {Reference*:{Number:0001123}
    User Name: {UserNames:{UserName*:Abe Lincoln}}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Paths:{Path*:[path]\761021.TIF}
    >>IRRELEVANT DATA 
    ...
    >>FileName: {Path*:[path]\761022.TIF}}}
    
    然后,您可以抛出原始文件内容(在变量$content中)并访问数据,如下所示:

    $res = $content | cfs -TemplateFile .\template.txt
    PS> $res[0].Reference.Number
    0001122
    PS> $res[0].Reference.UserNames.UserName.value
    George Washington
    Martha Washington
    PS> $res[0].Reference.Paths.Path.value
    [path]\761019.TIF
    [path]\761020.TIF
    

    在预览表单中使用此命令有点笨拙,因为它希望在默认情况下显示
    Extent
    属性,我认为您只需要调试模板。

    1。现有的脚本在哪里?2.如果您已经在解析文本,那么您应该创建具有属性的对象,并使用
    导出CSV
    ,而不创建自己的“CSV字符串”。那样更干净。3.如何处理csv中的多个文件路径和用户名?用户名字段中是否有任何特殊分隔符,或者您是否正在为同一文档创建多个记录(第一个示例中的用户名*路径=4)?1。现有的脚本在哪里?2.如果您已经在解析文本,那么您应该创建具有属性的对象,并使用
    导出CSV
    ,而不创建自己的“CSV字符串”。那样更干净。3.如何处理csv中的多个文件路径和用户名?用户名字段中是否有特殊的分隔符,或者您是否正在为同一文档创建多个记录(第一个示例中的用户名*路径=4)?我正在测试这段代码,它看起来工作得相当好。它确实在每个数组项的末尾包含下一条记录的“开始”,但不确定这是否是一个大问题,因为我将只提取每个对象中的一些数据。我确实需要对代码做一个更改,使其运行时不会出现错误:“Add Member-InputObject$Record-type NoteProperty-Name$Matches[1]-value@($Matches[2])。我正在运行更多的测试,但这看起来已经比我的文本解析更好了。我正在测试这段代码,它看起来工作得相当好。它确实在每个数组项的末尾包含下一条记录的“开始”,但不确定这是否是一个大问题,因为我将只提取每个对象中的一些数据。我确实需要对代码做一个更改,使其运行时不会出现错误:“Add Member-InputObject$Record-type NoteProperty-Name$Matches[1]-value@($Matches[2])。我正在运行更多的测试,但这看起来已经比我的文本解析更好了。