【问题标题】:Find out Text data in CSV File Numeric Columns in Powershell在 Powershell 的 CSV 文件数字列中查找文本数据
【发布时间】:2020-02-07 02:46:25
【问题描述】:

我是 powershell 的新手。 我试图通过找出我的数字字段中是否有任何文本值来验证我的 CSV 文件。我可以用列定义为数字。

这是我这样的源数据

ColA      ColB    ColC      ColD
23        23       ff       100
2.30E+01  34    2.40E+01    23
df        33      ss        df
34        35      36       37

我需要这样的输出(只有在任何列中找到的文本值)

ColA         ColC       ColD
2.30E+01      ff        df
df           2.40E+01   
              ss    

我尝试了一些代码但没有得到任何结果,只得到一些输出,如下所示

System.Object[]


---------------                                                                                                                                                                      
                                                        xxx fff' ddd 3.54E+03 

                                                                                                ...

这就是我正在尝试的

#
cls

function Is-Numeric ($Value) {
    return $Value -match "^[\d\.]+$"
}

$arrResult = @()
$arraycol = @()

$FileCol = @("ColA","ColB","ColC","ColD")

$dif_file_path = "C:\Users\$env:username\desktop\f2.csv"

#Importing CSVs

$dif_file = Import-Csv -Path $dif_file_path -Delimiter ","

############## Test Datatype (Is-Numeric)##########

 foreach($col in $FileCol)
  {
  foreach ($line in $dif_file) {

    $val = $line.$col

     $isnum = Is-Numeric($val)

    if ($isnum -eq $false) {
   $arrResult +=  $line.$col
   $arraycol += $col

    }
 }
 }
   [pscustomobject]@{$arraycol = "$arrResult"}| out-file "C:\Users\$env:username\Desktop\Errors1.csv" 
####################

有人可以指导我正确的方向吗? 谢谢

【问题讨论】:

    标签: powershell


    【解决方案1】:

    你可以试试这样的,

    function Is-Numeric ($Value) {
        return $Value -match "^[\d\.]+$"
    }
    
    $dif_file_path = "C:\Users\$env:username\desktop\f2.csv"
    
    #Importing CSVs
    
    $dif_file = Import-Csv -Path $dif_file_path -Delimiter ","
    
    #$columns = $dif_file | Get-member -MemberType 'NoteProperty' | Select-Object -ExpandProperty 'Name'
    # Use this to specify certain columns
    $columns = "ColB", "ColC", "ColD"
    
    foreach($row in $dif_file) {
      foreach ($col in $columns) { 
        if ($col -in $columns) {
          if (!(Is-Numeric $row.$col)) { 
            $row.$col = "" 
          }
        }
      } 
    } 
    
    $dif_file | Export-Csv C:\temp\formatted.txt 
    
    1. 随时查找列名
    2. 查找每行中每个列的值,如果不是数字,则更改为“”
    3. 导出的更新文件。

    【讨论】:

    • 感谢 Jawad,它看起来更接近我的要求。但是我只需要在文件中查找应该是 Numeric 的特定列,而不是所有列,因为还有很多文本列。为了解决这个问题,在我的示例代码中,我使用了一个仅包含那些特定列(colA、ColB、ColC、ColD)的数组来查找。谢谢。
    • @Saim 您可以通过更新 $columns 变量来使用特定的列。我想你已经有了。如果您更新变量 $columns,脚本的其余部分将按照您的需要运行。
    • 感谢 Jawad 的快速响应。按照您的建议,我尝试使用此代码中的特定列。对于每一行,我都收到以下错误,例如------------ 异常设置“ColA”:“在此对象上找不到属性 'ColA'。验证该属性是否存在并且可以设置。 "在 line:19 char:7 + $row.$col = "" + ~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting
    • @Saim 不使用集合,而是使用数组。请参阅我定义 $columns 的帖子中的代码。我测试过,现在似乎可以正常工作了
    • Jawad,我已经在使用我在代码中提到的数组,但得到相同的错误。使用文件时没问题,但使用数组中的项目时会出错。我在使用/创建数组时做错了什么?谢谢
    【解决方案2】:

    我认为不显示没有数据的列会带来挑战。您可以执行以下操作:

    $csv = Import-Csv "C:\Users\$env:username\desktop\f2.csv"
    $finalprops = [collections.generic.list[string]]@()
    
    $out = foreach ($line in $csv) {
        $props = $line.psobject.properties | Where {$_.Value -notmatch '^[\d\.]+$'} |
            Select-Object -Expand Name
        $props | Where {$_ -notin $finalprops} | Foreach-Object { $finalprops.add($_) }
        if ($props) {
            $line | Select $props
        }
    $out | Select-Object ($finalprops | Sort)
    

    鉴于Format-Table 或表格输出的性质,您只能看到集合中第一个对象的属性。所以如果object1只有ColA,而object2有ColAColB,你只会看到ColA

    【讨论】:

      【解决方案3】:

      您想要的输出顺序与输入 CSV 完全不同;您不是通过第一次出现来跟踪错误的文本数据,而是通过列顺序,这需要一些额外的步骤。

      test.csv 文件内容:

      ColA,ColB,ColC,ColD
      23,23,ff,100
      2.30E+01,34,2.40E+01,23
      df,33,ss,df
      34,35,36,37
      

      经过测试符合您的描述的示例代码:

      $csvIn = Import-Csv "$PSScriptRoot\test.csv";
      
      # create working data set with headers in same order as input file
      $data  = [ordered]@{};
      $csvIn[0].PSObject.Properties | foreach {
          $data.Add($_.Name, (New-Object System.Collections.ArrayList));
      };
      
      # add fields with text data
      $csvIn | foreach {
          $_.PSObject.Properties | foreach {
              if ($_.Value -notmatch '^-?[\d\.]+$') {
                  $null = $data[$_.Name].Add($_.Value);
              }
          }
      }
      
      $removes  = @(); # remove `good` columns with numeric data
      $rowCount = 0;   # column with most bad values
      $data.GetEnumerator() | foreach { 
          $badCount = $_.Value.Count;
          if ($badCount -eq 0) { $removes  += $_.Key; }
          if ($badCount -gt $rowCount) { $rowCount = $badCount; }
      }
      $removes | foreach { $data.Remove($_); }
      
      0..($rowCount - 1) | foreach {
          $h = [ordered]@{};
          foreach ($key in $data.Keys) {
              $h.Add($key, $data[$key][$_]);
          }
          [PSCustomObject]$h;
      } | 
      Export-Csv -NoTypeInformation -Path "$PSScriptRoot\text-data.csv";
      

      输出文件内容:

      "ColA","ColC","ColD"
      "2.30E+01","ff","df"
      "df","2.40E+01",
      ,"ss",
      

      【讨论】:

      • 感谢 Kuujinbo,我正在努力理解您的代码。这里只有一个问题是我只需要几列来测试而不是整个文件。在这种情况下,ColA",ColB,"ColC","ColD 只是源文件的子集,这就是我在示例代码中使用数组的原因。
      • 最后我设法只导入了所需的列,现在它工作得很好。非常感谢您的帮助
      • 在您的代码中没有寻找任何其他特殊字符,例如
      • @Saim - 更新答案以说明所有非数字,但允许使用 - 字符表示负数。
      【解决方案4】:

      @Jawad,我终于试过了

      function Is-Numeric ($Value) {
          return $Value -match "^[\d\.]+$"
      }
      $arrResult = @()
      $columns = "ColA","ColB","ColC","ColD"
      $dif_file_path = "C:\Users\$env:username\desktop\f1.csv" 
      $dif_file = Import-Csv -Path $dif_file_path -Delimiter "," |select  $columns
      $columns = $dif_file | Get-member -MemberType 'NoteProperty' | Select-Object -ExpandProperty 'Name'
      foreach($row in $dif_file) {
        foreach ($col in $columns) { 
        $val = $row.$col
        $isnum = Is-Numeric($val)
             if ($isnum -eq $false) { 
              $arrResult += $col+ " " +$row.$col
            }}} 
       $arrResult | out-file "C:\Users\$env:username\desktop\Errordata.csv"
      

      我在输出文件中得到了正确的结果,顺序很模糊

      ColA ss
      ColB 5.74E+03
      ColA ss
      ColC rrr
      ColB 3.54E+03
      ColD ss
      ColB 8.31E+03
      ColD cc
      

      任何想法来获得正确的格式?谢谢 注意:使用您建议的代码,我会得到包含所有数据的完整源文件,而不是具体的错误数据。

      【讨论】:

        猜你喜欢
        • 2012-07-03
        • 1970-01-01
        • 2016-08-22
        • 2022-11-22
        • 1970-01-01
        • 1970-01-01
        • 2017-05-26
        • 2013-10-11
        相关资源
        最近更新 更多