【问题标题】:powershell extract text between two stringspowershell 提取两个字符串之间的文本
【发布时间】:2016-08-13 06:39:55
【问题描述】:

我知道以前有人问过这个问题,但我无法得到任何我在工作中看到的答案。我有一个包含数千行的 JSON 文件,并且希望每次出现两个字符串时都简单地提取它们之间的文本(很多)。

作为一个简单的例子,我的 JSON 如下所示:

    "customfield_11300": null,
    "customfield_11301": [
      {
        "self": "xxxxxxxx",
        "value": "xxxxxxxxx",
        "id": "10467"
      }
    ],
    "customfield_10730": null,
    "customfield_11302": null,
    "customfield_10720": 0.0,
    "customfield_11300": null,
    "customfield_11301": [
      {
        "self": "zzzzzzzzzzzzz",
        "value": "zzzzzzzzzzz",
        "id": "10467"
      }
    ],
    "customfield_10730": null,
    "customfield_11302": null,
    "customfield_10720": 0.0,

所以我想输出“customfield_11301”和“customfield_10730”之间的所有内容:

      {
        "self": "xxxxxxxx",
        "value": "xxxxxxxxx",
        "id": "10467"
      }
    ],
      {
        "self": "zzzzzzzzzzzzz",
        "value": "zzzzzzzzzzz",
        "id": "10467"
      }
    ],

我试图让它尽可能简单 - 所以不要关心输出中显示的括号。

这就是我所拥有的(输出比我想要的多):

$importPath = "todays_changes.txt"
$pattern = "customfield_11301(.*)customfield_10730"

$string = Get-Content $importPath
$result = [regex]::match($string, $pattern).Groups[1].Value
$result

【问题讨论】:

  • 为什么不将 JSON 解码为对象并直接寻址属性?
  • 快速回答是 - 将您的贪婪捕获 (.*) 更改为非贪婪 - (.*?)。应该这样做。
  • 很高兴它有帮助。请随意在下面将我的答案标记为已接受

标签: regex powershell


【解决方案1】:

第一个问题是Get-Content 管道将逐行而不是一次提供全部内容。您可以通过管道 Get-ContentOut-String 将整个内容作为单个字符串获取,并对内容执行正则表达式。

您的问题的有效解决方案是:

Get-Content .\todays_changes.txt | Out-String | % {[Regex]::Matches($_, "(?<=customfield_11301)((.|\n)*?)(?=customfield_10730)")} | % {$_.Value}

输出将是:

": [
  {
    "self": "xxxxxxxx",
    "value": "xxxxxxxxx",
    "id": "10467"
  }
],
"

": [
  {
    "self": "zzzzzzzzzzzzz",
    "value": "zzzzzzzzzzz",
    "id": "10467"
  }
],
"

【讨论】:

    【解决方案2】:

    这是一个 PowerShell 函数,它将在两个字符串之间找到一个字符串。

    function GetStringBetweenTwoStrings($firstString, $secondString, $importPath){
    
        #Get content from file
        $file = Get-Content $importPath
    
        #Regex pattern to compare two strings
        $pattern = "$firstString(.*?)$secondString"
    
        #Perform the opperation
        $result = [regex]::Match($file,$pattern).Groups[1].Value
    
        #Return result
        return $result
    
    }
    

    然后你可以像这样运行函数:

    GetStringBetweenTwoStrings -firstString "Lorem" -secondString "is" -importPath "C:\Temp\test.txt"
    

    我的 test.txt 文件中包含以下文本:

    Lorem Ipsum 只是印刷和排版行业的虚拟文本。

    所以我的结果:

    Ipsum

    【讨论】:

      【解决方案3】:

      快速的答案是 - 将你的贪婪捕获 (.*) 更改为非贪婪 - (.*?)。应该这样做。

      customfield_11301(.*?)customfield_10730
      

      否则捕获将尽可能多地吃掉,导致它一直持续到最后一个customfield_10730

      问候

      【讨论】:

      • 使用这种方法,如果我在一行中有多次相同的模式,它只会返回第一次出现。关于如何将其应用于同一行中的多次出现的任何想法?
      【解决方案4】:

      你需要让你的 RegEx Lazy

      customfield_11301(.*?)customfield_10730
      

      Live Demo on Regex101

      您的正则表达式 贪婪。这意味着它将找到customfield_11301,然后进行直到找到最后一个 customfield_10730

      这是贪婪与懒惰正则表达式的更简单示例:

      # Regex (Greedy): [(.*)]
      # Input:          [foo]and[bar]
      # Output:         foo]and[bar
      
      # Regex (Lazy):   [(.*?)]
      # Input:          [foo]and[bar]
      # Output:         "foo" and "bar" separately
      

      您的正则表达式与第一个非常相似,它捕获了太多,而这个新的正则表达式捕获的数据量可能最少,因此可以按您的预期工作

      【讨论】:

      • 感谢您的帮助,@ClasG 在您之前几分钟就回答了,所以我会接受他的回答。但特别感谢您提供的 regex101 演示链接,它确实帮助我理解了正在发生的事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      • 2019-12-25
      • 2015-05-10
      • 2018-11-02
      • 1970-01-01
      • 2016-08-02
      相关资源
      最近更新 更多