在PowerShell中按模式分割字符串

时间:2018-10-22 23:50:58

标签: string powershell split

我在PowerShell中有一个相当长的字符串,需要拆分。每个部分均以日期mm/dd/yyyy hh:mm:ss AM开头。本质上,我想做的是获取字符串中的最新消息。我不需要保留日期/时间部分,因为我已经在其他地方了。

这是字符串的样子:

10/20/2018 1:22:33 AM
Some message the first one in the string

It can be several lines long
With multiple line breaks

But this is still the first message in the string

10/21/2018 4:55:11 PM
This would be second message
Same type of stuff

But its a different message

我知道如何在特定字符上分割字符串,但我不知道如何在日期/时间等模式下进行

4 个答案:

答案 0 :(得分:3)

注意:

  • 下面的解决方案假定该部分不是 ,不一定是按时间顺序排序,因此您必须检查所有时间戳,以确定最近的时间戳。
  • 相比之下,如果您可以假设 last 消息是最新消息,请使用LotPings' much simpler answer

如果您不提前知道哪个部分的时间戳最近,最好采用逐行方法:

$dtMostRecent = [datetime] 0
# Split the long input string ($longString) into lines and iterate over them.
# If input comes from a file, replace 
#   $longString -split '\r?\n'
# with
#   Get-Content file.txt
# If the file is large, replace the whole command with
#   Get-Content file.txt | ForEach-Object { ... } 
# and replace $line with $_ in the script block (loop body).
foreach ($line in $longString -split '\r?\n') {
  # See if the line at hand contains (only) a date.     
  if ($dt = try { [datetime] $line } catch {}) {
    # See if the date at hand is the most recent so far.
    $isMostRecent = $dt -ge $dtMostRecent
    if ($isMostRecent) {
      # Save this time stamp as the most recent one and initialize the
      # array to collect the following lines in (the message).
      $dtMostRecent = $dt 
      $msgMostRecentLines = @()
    }
  } elseif ($isMostRecent) {
    # Collect the lines of the message associated with the most recent date.
    $msgMostRecentLines += $line
  }
}

# Convert the message lines back into a single, multi-line string.
# $msgMostRecent now contains the multi-line message associated with
# the most recent time stamp.
$msgMostRecent = $msgMostRecentLines -join "`n"

请注意如何使用try { [datetime] $line } catch {}来尝试将行转换为[datetime]实例,并在无法实现的情况下静默失败,在这种情况下,$dt被分配了{{1} },在布尔上下文中解释为$null

无论当前有效的区域性如何,此技术都有效,因为PowerShell的强制类型转换从字符串进行强制转换时始终使用 invariant 区域性,并且输入中的日期采用了不变性区域性可以理解的格式之一

与之相反,$False运算符在-as的使用上更加方便-Esperento57指出, 意外地对文化敏感。
this GitHub issue中讨论了这种令人惊讶的行为。

答案 1 :(得分:1)

假设[datetime]节升序,
用RegEx拆分它们并获得最后一个就足够了

((Get-Content .\test.txt -Raw) -split "\d+/\d+/\d{4} \d+:\d+:\d+ [AP]M`r?`n")[-1]

基于存储在文件test.txt中的示例字符串的输出

This would be second message
Same type of stuff

But its a different message

答案 2 :(得分:0)

您可以按时间戳记模式将其拆分,如下所示:

$arr =  $str -split  "[0-9]{1,2}/[0-9]{1,2}/[0-9]{1,4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [AaPp]M\n"

答案 3 :(得分:-1)

据我所知,您不能为此使用任何静态String方法(例如Split())。我试图找到一个可以处理整个事情的正则表达式,但无法提出能完全分解的正则表达式。

因此,您需要一行一行地进行测试,以查看该行是否为日期,然后像下面这样将它们之间的行连接起来:

$fileContent = Get-Content "inputFile.txt"
$messages = @()
$currentMessage = [string]::Empty
foreach($line in $fileContent)
{
    if ([Regex]::IsMatch($line, "\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{2}:\d{2} (A|P)M"))
    {
        # The current line is a date, the current message is complete
        # Add the current message to the output, and clear out the old message 
        # from your temporary storage variable $currentMessage
        if (-not [string]::IsNullOrEmpty($currentMessage))
        {
            $messages += $currentMessage
            $currentMessage = [string]::Empty
        }
    }
    else
    {
        # Add this line to the message you're building.
        # Include a new line character, as it was stripped out with Get-Content
        $currentMessage += "$line`n"
    }
}

# Add the last message to the output
$messages += $currentMessage

# Do something with the message
Write-Output $messages

由于所有这些的关键是要认识到给定的行是日期,因此是消息的开头,因此让我们再看一下正则表达式。 “ \ d”将匹配任何0-9的十进制字符,紧随其后的花括号表示需要匹配的十进制字符的数量。因此,“ \ d {1,2}”的意思是“寻找一个或两个十进制字符”,或者在这种情况下是一年中的月份。然后,我们寻找一个“ /”,另外1个或2个十进制字符-“ \ d {1,2}”,另一个“ /”,然后正好4个十进制字符-“ \ d {4}”。时间大致相同,小数点之间用“:”代替“ /”。最后,会有“ AM”或“ PM”,因此我们寻找“ A”或“ P”后跟“ M”,其正则表达式为“(A | P)M”

将所有内容组合在一起,您将获得“ \ d {1,2} / \ d {1,2} / \ d {4} \ d {1,2}:\ d {2}:\ d { 2}(A | P)M”来确定您是否在该行上有一个日期。我相信也可以使用[DateTime] :: Parse()确定该行是否为日期,但是那样您就不会对Regex感兴趣,并且需要try-catch。有关Powershell中正则表达式的更多信息(只是.NET正则表达式),请参见.NET Regex Quick Reference