【问题标题】:Extracting String between 2 Strings在2个字符串之间提取字符串
【发布时间】:2015-11-24 22:01:07
【问题描述】:

我正在尝试提取位于文件中其他两个字符串之间的字符串 字符串是“USE”和“GO”

这就是我想出来的:

$importPath = "SOMEPATH"
$pattern = "(?<=\*\*USE\*\*)[\s\S]*(?=\*\*GO\*\*)"

Get-Content $importPath | Foreach {if ([Regex]::IsMatch($_, $pattern)) { $arr += [Regex]::Match($_, $pattern)}}

$arr 

但是当执行此操作时,我什么也没得到

示例 SQL 脚本:

USE FIZNET
GO



DECLARE @Symbol_Type_Id SMALLINT

SELECT @Symbol_Type_Id = Symbol_Type_Id 
FROM dbo.SymbolTypes 
WHERE SymbolType = 'Indices - Asia'

UPDATE dbo.Currencies SET
Symbol_Type_Id = @Symbol_Type_Id
WHERE Currency = 'ASX'

GO

我希望 $arr 的值为“FIZNET”

【问题讨论】:

  • 您是否有示例字符串和预期的输出进行比较?同样在您的示例中,您有$path 使用Get-Content $importPath。您确定正在读取源文件并且它包含应该匹配的行吗?
  • 感谢编辑,这两个地方都是 $importPath,我验证了文件在该位置,它是一个简单的 SQL 脚本 im trying to extract the Database name from , the string will be from the Type : USE [DB NAME] GO And i like to extract the DB NAME so i know where to execute the script (different DBs 位于不同的服务器)
  • 您的样本中没有星号
  • USE 和 GO 是否在同一行...它们是否在文件中重复多次。?请附上文件的清理样本。
  • 添加示例,谢谢

标签: regex powershell


【解决方案1】:

您可以使用.* 正则表达式来匹配所有字符串。例如:

$importPath = "PATHNAME"
$pattern = "USE(.*)GO"

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

【讨论】:

  • 这不起作用,因为它是贪婪的,如果文件中有多个匹配项。应该等待 op 包含示例数据。
  • 示例添加到原始帖子,谢谢
【解决方案2】:

作为一种替代方法,这可能会有所帮助:

$Result = 'SELECT USE SELECT * FROM MyTable GO OTHER STUFF' -split 'USE|GO' |
    Select-Object -Skip 1 -First 1

# Remove space before and after
$Result.Trim()

输出是:

SELECT * FROM MyTable

【讨论】:

  • 输出会有一个前导和尾随空格,不是吗?
【解决方案3】:

这里有改进的余地,因为我们没有示例文件,但您的正则表达式模式似乎适用于这样的事情。

**USE**AdventureWorks2012**GO**

我怀疑这不是这些行在您的数据文件中的外观。可能是跨行拆分?我想向您介绍Select-String 以帮助缓解这种情况。考虑以下我从TechNet 创建的坏 sql 文件(用于测试)。

USE AdventureWorks2012
GO
DECLARE @MyMsg VARCHAR(50)
SELECT @MyMsg = 'Hello, World.'
GO -- @MyMsg is not valid after this GO ends the batch. Just because.

**USE** AdventureWorks2012;
**GO**
DECLARE @MyMsg VARCHAR(50)
SELECT @MyMsg = 'Hello, World.'

现在,在该文件中,我们有一个带有星号的示例和一个没有星号的示例。您的正则表达式期待**,因此我提供了涵盖这两种情况的解决方案。

# Test with one pattern and comment out the other
$pattern = "(?<=USE\*\*)([\s\S]*?)(?=\*\*GO)"
$pattern = "(?<=USE)([\s\S]*?)(?=GO)"

(Get-Content $path -Raw | Select-String -Pattern $pattern -AllMatches -CaseSensitive).Matches.Value | ForEach-Object{$_.Trim()}

使用与您的文本实际匹配的$pattern。如果它确实跨行传播,这将在我们将文件作为一个字符串读取时起作用(对于大文件会很慢)。 -CaseSensitive 应该会在文本中有注释的情况下提供帮助,例如“因为”这个词。另一个重要的变化是匹配是 non-greedy,以防文件中有多个匹配项。

模式应分别返回AdventureWorks2012;AdventureWorks2012

使用您的示例进行编辑

根据我上面的解释使用以下代码,您可以获得预期的结果。

$pattern = "(?<=USE)([\s\S]*?)(?=GO)"
$arr = (Get-Content $path -Raw | Select-String -Pattern $pattern -AllMatches -CaseSensitive).Matches.Value | ForEach-Object{$_.Trim()}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多