Powershell在String中搜索并提取字符串的特定值

时间:2019-01-27 20:05:02

标签: regex string powershell

我有一个很大的文件,其中包含很多行。例如:

ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this

我想从每一行中提取以下信息:

ts=,system= & something=,但=之后的值始终会更改。

我已经尝试过了,但是无法正常工作:

$found = $string -match '.*system="(\d+)".*' if ($found) { $system= $matches[1]}

3 个答案:

答案 0 :(得分:5)

这是另一个解决方案。 [ grin ]它使用ConvertFrom-StringData cmdlet将输入解析为对象。然后它仅创建一个需要道具的[PSCustomObject]。最后,它将每个对象发送到$ Results集合。

在这种情况下,最终定制对象的构造使以下信息不重要,但重要的是要知道ConvertFrom-StringData cmdlet的输出是标准哈希表。这意味着对象的顺序几乎可以肯定不是原始顺序。 不要期望事物按照它们在源中出现的顺序

[edit =添加了一条新的数据行,该行具有嵌入的空格和更新的-replace模式来处理。]

# fake reading in a text file
#    in real life, use Get-Content
$InStuff = @(
    'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this'
    'ts=2019-01-16 network=1.1.1.2 system=PC-001 pid=100 bugReq=dasf something=OtherElse maybe=this'
    'ts=2019-01-16 network=1.1.1.66 system=PC-666 pid=100 bugReq=dasf something=ThisELse maybe=this'
    'ts=2019-01-16 network=1.1.1.3 system=PC-123 pid=100 bugReq=dasf something=AnotherElse maybe=this'
    'ts=2019-01-16 network=1.1.1.4 system=PC-004 Oo-LaLa another value with WhiteSpace id=100 bugReq=dasf something=Else-ish with Whitespace'
    )

$Results = foreach ($IS_Item in $InStuff)
    {
    # this requires that spaces ONLY be found as delimiters
    #    if you have embedded spaces, some sort of data format adjustment will be required
    #    now there is a need for handline embedded whitespace
    #$IS_Item -replace ' ', [environment]::NewLine |
    $IS_Item -replace '(\w{1,}=)', ('{0}{1}' -f [environment]::NewLine, '$1') |
        ConvertFrom-StringData |
        ForEach-Object {
            [PSCustomObject]@{
                TS = $_.ts
                System = $_.system
                Something = $_.something
                }
            }
    }

$Results

在屏幕上输出...

TS         System                                       Something               
--         ------                                       ---------               
2019-01-16 irgendwas                                    else                    
2019-01-16 PC-001                                       OtherElse               
2019-01-16 PC-666                                       ThisELse                
2019-01-16 PC-123                                       AnotherElse             
2019-01-16 PC-004 Oo-LaLa another value with WhiteSpace Else-ish with Whitespace

这是简单对象的适当集合,因此它将Export-CSV非常整洁。 [咧嘴]

答案 1 :(得分:1)

假设每行的键值对列表仅包含值,而没有嵌入的空格或引号

# Sample input line.
$line = 'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid1=100 bugReq=dasf something=else maybe=this'

# Parse the line into key-value pairs and create a variable for each.
$i = 0
foreach ($keyOrValue in $line -split '[= ]') {
  if ($i++ % 2 -eq 0) { $varName = $keyOrValue }
  else                { Set-Variable $varName $keyOrValue }
}

# $ts now contains '2019-01-16', $network '1.1.1.1', $system 'irgendwas', ...

请注意,我是如何稍微修改示例输入行以将pid更改为pid1,因为PowerShell不允许您创建$PID变量,因为它是< em> automatic 变量,反映当前会话的PID(进程ID)。

另一个选择(也可以避免变量名冲突)是为每个输入行创建一个 hashtable

# Sample input line.
$line = 'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this'

# Parse the line into key-value pairs and create a variable for each.
$htValues = @{} # Initialize the hashtable.
$i = 0
foreach ($keyOrValue in $line -split '[= ]') {
  if ($i++ % 2 -eq 0) { $varName = $keyOrValue }
  else                { $htValues[$varName] = $keyOrValue }
}

# $htValues now has keys 'ts', 'network', 'system' with corresponding
# values, so you can access $htValues.ts to get '2019-01-16', for instance.

这种方法的另一个优势是可以借用自己收集整体数组中的各个行创建的哈希表(例如,$hashTableArray = foreach ($line in ...) { ... }-尽管一个非常大的文件,可能无法选择。

借用Lee_Dailey's answer的想法,您可以选择使用ConvertFrom-StringData cmdlet创建哈希表,之后首先借助{{1}将每个键值对放在自己的行中}运算符:

-replace

caveat re ConvertFrom-StringData是它解释$htValues = ConvertFrom-StringData ($line -replace ' ', "`n") 字符的原因。作为开始的转义序列;例如,诸如\的值会破坏命令:

b\c

从正面来看,使用Convertfrom-StringData 'a=b\c' # ERROR: "parsing 'b\c' - Missing control character." 比使用ConvertFrom-StringData进行手动解析要快得多。


顺便说一句:PowerShell的foreach cmdlet用于一一读取行(默认情况下)很方便,但是

要更快地处理(大)文本文件的行,请使用:

Get-Content

答案 2 :(得分:0)

所以您显示给我的日志的工作方式看起来像我们可以从中剪切和粘贴的三个部分 对象,可以从新行返回 密钥对,可以从空白处返回 密钥,可以通过删除=

返回

我使用这种想法为这种情况编写了一个函数

function ConvertTo-PsObjectArrayList($Text,$TextObjectSeparator,$KeyPairSeparator,$KeySeparator){
    $ArrayList = New-Object System.Collections.ArrayList
    $TestData -split $TextObjectSeparator | %{
        $PsObject = new-object System.Management.Automation.PSObject
        $_ -split $KeyPairSeparator | %{      
            $KeyPair = $_ -split $KeySeparator
            $PsObject | Add-Member -MemberType NoteProperty -Name $KeyPair[0] -Value $KeyPair[1]
        }
        $ArrayList.Add($PsObject) | out-null
    }
    return $ArrayList
}

$TestData = @'
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this
ts=2019-01-16 network=1.1.2.1 system=irgendwas pid=130 bugReq=dasf something=else
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=150 bugReq=dasf something=else maybe=this
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=110 bugReq=dasf something=else
'@

ConvertTo-PsObjectArrayList -Text $TestData -TextObjectSeparator "`r`n" -KeyPairSeparator " " -KeySeparator "=" | select TS, System, Something

这将返回

ts         system    something
--         ------    ---------
2019-01-16 irgendwas else     
2019-01-16 irgendwas else     
2019-01-16 irgendwas else     
2019-01-16 irgendwas else