【问题标题】:String trim and split字符串修剪和拆分
【发布时间】:2018-02-06 05:20:49
【问题描述】:

我有一个文本文件,我需要从中获取值。

示例文本文件:

[网站 01] DBServer=LocalHost DBName=数据库01 用户名=管理员 密码=qwerty [网站 02] 数据库服务器=192.168.0.10 DBName=数据库02 用户名=管理员 密码=qwerty

目前,我的代码会读取文件并将每个作为数组条目放置在找到的每一行 DBServer= 中,并且此文本文件可以包含多个站点:

$NumOfSites = Get-Content $Sites |
              Select-String -Pattern "DBServer=" -Context 0,3
$i = 0
$NumOfSites | ForEach-Object {
    $svr  = $NumOfSites[$i] -isplit "\n" |
            % { ($_ -isplit 'DBServer=').Trim()[1] }
    $db   = $NumOfSites[$i] -isplit "\n" |
            % { ($_ -isplit 'DBName='.Trim())[1] }
    $uid  = $NumOfSites[$i] -isplit "\n" |
            % { ($_ -isplit 'Username='.Trim())[1] }
    $pswd = $NumOfSites[$i] -isplit "\n" |
            % { ($_ -isplit 'Password='.Trim())[1] }
    $i = $i+1
}

如果没有一些额外的空格或很好的字符串变量,我无法正确拆分每个属性。 我只需要从我拥有的文件示例的格式中提取信息以作为变量放入 SQL 连接行。

【问题讨论】:

  • 您发布的代码不完整。发布问题时,请确保您的代码是minimal reproducible example。此外,一些括号似乎放错了位置,尽管这不应该破坏代码。话虽如此,解析 INI 样式的文件是一个很好解决的问题。请做一些research

标签: powershell parsing split trim


【解决方案1】:

除了记录头(即[Site 01])之外,其余的都可以由ConvertFrom-StringData处理。我们可以将记录转换为直接在标题行上或多或少拆分的对象。 ConvertFrom-StringData 将多行字符串转换为哈希表,您可以将其转换为 [PSCustomObject] 和中提琴,您拥有易于使用的对象。

$NumOfSites = Get-Content $Sites -raw
$SiteObjects = $NumOfSites -split '\[.+?\]'|%{[PSCustomObject](ConvertFrom-StringData -StringData $_)}

然后您可以随意操作$SiteObjects(如果需要,可以输出到CSV,或使用Select-Object 过滤任何属性)。或者,如果您希望建立连接,您可以循环通过它来根据需要建立您的连接...

ForEach($Connection in $SiteObjects){
    $ConStr = "Server = {0}; Database = {1}; Integrated Security = False; User ID = {2}; Password = {3};" -f $Connection.DBServer.Trim(), $Connection.DBName.Trim(), $Connection.Username.Trim(), $Connection.Password.Trim()
    <Do stuff with SQL>
}

编辑:更新我的答案,因为示例文本已更改为添加 &lt;pre&gt;&lt;/pre&gt;。我们只需要删除这些,因为 OP 收到有关 null 值方法的错误,我们也将过滤 null。

$NumOfSites = Get-Content $Sites -raw
$SiteObjects = $NumOfSites -replace '<.*?>' -split '\[.+?\]' | ?{$_} |%{[PSCustomObject](ConvertFrom-StringData -StringData $_)}
ForEach($Connection in $SiteObjects){ 
    $svr = $Connection.DBServer.Trim() 
    $db  = $Connection.DBName.Trim() 
    $uid = $Connection.Username.Trim() 
    $pwd = $Connection.Password.Trim()
}

【讨论】:

  • 这个好主意 +1 需要 gc 的 -raw 参数。
  • 啊,是的,我已经更新了答案,将-raw 开关包含在Get-Content 中。谢谢你提醒我。
  • 我试过这个,但它似乎只在第一轮之后填充 $Connection var,并且我收到关于你不能在空值表达式上调用方法的错误。
  • $NumOfSites = 获取内容 $Sites -raw $SiteObjects = $NumOfSites -split '[.+?]'|%{[PSCustomObject](ConvertFrom-StringData -StringData $_)} ForEach( $SiteObjects 中的 $Connection){ $svr = $Connection.DBServer.Trim() $db = $Connection.DBName.Trim() $uid = $Connection.Username.Trim() $pwd = $Connection.Password.Trim( )
  • 对我创建的每个 var 重复第一次迭代时出错:您不能在空值表达式上调用方法。在 C:\Users\catalyph\Documents\PowerShell\SQLExecute\SQLexecute105 TEST.ps1:134 char:5 + $svr = $Connection.DBServer.Trim() + ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
【解决方案2】:

如果您只关心获取等号之后的值,这里有一个建议:

Get-Content Example.txt |
  ForEach-Object {
      Switch -Regex ($_) {
          'dbs.+=' { $svr = ($_ -replace '.+=').Trim()
          .. etc ..
      }
  }

Get-Content 通过管道传送到ForEach-Object 会将每一行解释为它自己的对象。


编辑:
你大部分时间都在那里,但没有必要-split

$NumOfSites = Get-Content $Sites | Select-String -pattern "DBServer=" -Context 0,3
$NumOfSites | ForEach-Object {
    Switch -Wildcard ($_) {
        'DBS*=' { $svr = ($_ -replace '.+=').Trim() }
        'DBN*=' { $db  = ($_ -replace '.+=').Trim() }
        'U*='   { $uid = ($_ -replace '.+=').Trim() }
        'P*='   { $pw  = ($_ -replace '.+=').Trim() }
    }
}

【讨论】:

  • 这捕获了第一个站点变量,但随后保留了它们,并且在下一个循环返回时它们没有改变。
猜你喜欢
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
相关资源
最近更新 更多