【问题标题】:How to extract dynamic substrings with multiples occurences within a variable如何提取变量中多次出现的动态子字符串
【发布时间】:2020-12-02 01:40:51
【问题描述】:

带着挑战学习 Powershell:
我正在 Powershell-ISE(在 Windows 服务器上)中做一个 GUI,以避免一直键入命令。目标是根据我从 unix 服务器收到的加密文件显示一些信息。
到目前为止,我能够在一个巨大的标签框中显示这些文件的内容,但我很难解析它。
稍后我需要将该输出格式化为更易读的表格,而不是一行,但由于我已经在解析中苦苦挣扎,我将其保留在另一篇文章中。
我想这与我读过的关于“简单”字符串提取的其他帖子或关于 -match 和 $matches 的官方文档略有不同。如果我使用正则表达式模式,我总是以整行结束或什么都没有(模式很难定义,因为目标前后有很多单词)。
另外,当我使用帖子中的类似代码时,它在纯字符串上总是更容易,但这里我的变量包含输入($Myinput),可能在我试图捕获的一些值的末尾带有隐藏字符,如 \n(文件来自 unix,并且那里有一只猫命令用新行正确显示它.. [不,我可能不会在 unix 服务器上执行此脚本,我被那个带有基本 powershell 组件的 windows 服务器卡住了])。

总而言之,我被困在有点太简单的帖子和其他太高级的帖子之间,我无法理解。
如果您能帮助我解除逻辑障碍,我将不胜感激,我将在下面重新发布进度。

A. 变量包含如下内容:

此文件包含 2 人 名字:Group1 创建日期:2010 年 7 月 23 日 word : word word word : word word 自:Thu Jan 01 01:00:00 CET 2004 直到:Mon Jan 01 00:59: 59 CET 2011 word word word ******************************************* 第一名称:word.word 创建日期:2020 年 7 月 23 日单词名称:单词单词单词单词:单词单词单词从:Fri Nov 02 01:00:00 CET 2010 直到:Wed Jan 01 00:59:59 CET 2011 ** ***************************************** 名字:word.word 创建日期: 30-Jun-2020 word: word word word word name : word word word from: Tue Jun 30 11:14:33 CEST 2010 until: Mon Sep 28 11:14:33 CEST 2021 ********** ******************************************

注意:它就像一棵树,上面有一群人,下面有一群人。一个组或一个人是一个条目。
注意:我需要获取每个条目的名字和日期。


B. 我试过的(这里不是所有的试验,会太长):

我只知道人数和名字,最后我还需要“从”和“直到”。
目前我将它们全部按类型保存在数组中,但我认为最好按“人”使用数组(?)

    #I take the number of people
    $people = ([regex]::matches($Myinput,"\d+") | %{$_.value})
    $labelOutputBox.AppendText("Number of entries: " + $people[0])
    #result not optimized as I get all the digits from that input, and display only the first occurence
    
    #method1 for names
    ([regex]::matches($Myinput,"First name:\s(?<FirstNames>.*)\sCreation date") | %{$_.value})
    $labelOutputBox.AppendText("1/ FirstNames: ")
    $labelOutputBox.AppendText($matches['FirstNames'])
    # result empty
      
    #method2 for names
    $SearchStart="First name: "
    $SearchEnd="Creation"
    $Myinput -match "(?s)$SearchStart(?<content>.*)$SearchEnd"
    $result=$matches['content']
    $labelOutputBox.AppendText("2/ FirstNames: ")
    $labelOutputBox.AppendText($result)
    #result empty, this is where I think a hidden character before the $SearchEnd

注意:我也不懂 $matches 数组,当使用 时,我怎么能显示几个“名字”,因为我不能索引它,我也试过 [0] 或 ...

我尝试得越多,我就越困惑。
我还尝试将问题分成更小的问题以简化流程,但它并不能反映真实情况,有时会有不同的行为。
我的逻辑有什么问题?和搜索模式?
我应该重新考虑我处理这件事的方式吗?我的意思是,如果我从另一个角度看待问题,由人和 foreach 人......然后我会被困在同一个人/姓名中的太多结果,而下一个人的结果相同。

抱歉,如果这有点长,但正如您所见,请将其分开并放宽大局。
先感谢您。欢迎任何评论。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    关于您正在使用的一些技术的一些基本信息:

    • 语法(?&lt;Name&gt;something) 用于创建命名捕获组。这里捕获组名称是Name,它应用于匹配something
      • 要访问每个捕获组匹配项,您可以使用以下语法:
        • [regex]::Matches('something','(?&lt;MyName&gt;something)').Groups | Where Name -eq 'MyName' | Foreach-Object { $_.Value }
    • 使用[regex]::Matches() 时,如果找到匹配项,将返回Match 对象的集合。每个对象都可以使用从 0 开始的索引来访问,例如[regex]::Matches()[0] 用于第一个对象或[regex]::Matches()[3] 用于第四个对象。
    • [regex]::Match() 返回一个 Match 对象的集合。考虑到所有捕获组,它只会返回找到的第一个匹配项。因此,如果您有 2 个捕获组,它将返回捕获组 0、1​​ 和 2(0 是整个匹配项)。
      • 例如[regex]::Match('111112111121112','1(2)'),只匹配12(捕获组0)和2(捕获组1)一次产生一个Match对象。 [regex]::Matches 将返回 3 个 Match 对象。
    • 属性的层次结构是Match Objects -> Groups -> Name,Value。因此,这意味着您必须遍历 Match 对象,然后遍历 Groups
    • $matches 是一个自动变量。当-match 运算符用于单个字符串并找到成功匹配时,它会更新。然后您可以检索$matches$matches.capturegroup 等。如果没有找到匹配项,它将保留其当前值,即找不到匹配项时不会更新!
    • .* 是任意字符的贪婪匹配。 .*? 是任何字符的惰性(不贪婪)匹配。总结一下差异,贪婪匹配将尽可能长时间地继续匹配。惰性匹配会尽快停止匹配。
      • '11121112' -match '\d*2' 将匹配 11121112'11121112' -match '\d*?2' 将匹配 1112
    • -match 在用于单个字符串时返回TrueFalse。当用于集合时,它将返回匹配项。 要禁止输出,请使用 $null = 'something' -match 'something''something' -match 'something' | Out-Null[void]('something' -match 'something')null 机制
    • (?s) 是一个模式修饰符。语法为(?modifierflag)s 是单行的。修饰符之后的任何匹配项都应用修饰符。 s 的优点是 . 字符将匹配换行符(回车和换行)。因此,如果您有一个以换行符作为换行符的字符串,那么如果您想跨行跨越匹配项,则可能需要这样做。

    为了使这些示例中的任何一个起作用,假设$MyInput 是一个单独的字符串。

    使用[regex]::Matches():

    [regex]::matches($Myinput,'First name:\s(?<FirstNames>.*?)\sCreation date') | Foreach-Object {
        ($_.Groups | Where Name -eq 'FirstNames').Value # Your capture group values
    }
    

    使用$matches

    $null = $Myinput -match "(?s)$SearchStart(?<content>.*)$SearchEnd"
    # If the above found a match, then the following will contain the content capture group
    $matches.content
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多