动力 shell |csv文件编辑A列中的每一行以设置最大字符数

wf82jlnq  于 2022-12-06  发布在  Shell
关注(0)|答案(2)|浏览(154)
$lower = Import-Csv "C:\\Users\\X\\Desktop\\U\\cvv.csv"  
$lower | ForEach-Object {

       src['A']=src['A'].str[:20].str.lower()
    
     } 

$lower |
Export-Csv -Path "C:\\Users\\X\\Desktop\\U\\cvv2.csv"

我试过这个方法,但不管用。
我想如果它是超过20个字符删除和匹配它的最大20。

yzuktlbb

yzuktlbb1#

看起来您混合了Python和PowerShell语法。
您可能正在寻找:

$lower = Import-Csv 'C:\Users\X\Desktop\U\cvv.csv'
$lower | ForEach-Object {
  $_.A = $_.A.Substring(0, 20).ToLower() 
}
# ... Export-Csv command omitted.

但是,如果某些属性值的字符数 * 少于 * 20个,则需要做更多的工作,即避免.Substring()方法抛出的异常。

$lower = Import-Csv 'C:\Users\X\Desktop\U\cvv.csv'
$lower | ForEach-Object {
  $val = if ($_.A.Length -gt 20) { $_.A.Substring(0, 20) } else { $_.A }
  $_.A = $val.ToLower() 
}
  • 下面是一个较短的替代方法,但如果 * 许多 * 输入字符串都短于20个字符,则执行效果会很差,因为异常处理在性能方面开销很大:
  • try { $_.A.Substring(0, 20) } catch { $_.A }
  • PowerShell(Core)7+ 中,您可以将if语句缩短为:
  • $_.A.Length -gt 20 ? $_.A.Substring(0, 20) : $_.A
可选阅读:比较了各种减法字符串提取方法的性能。
  • 在PowerShell中提取子字符串的方法有多种,它们在详细程度和性能方面差别很大:
  • 然而,这两个方面并不相关,事实上,在这种情况下,最详细的方法是最快的。
  • 从广义上讲,这些方法可分为:
  • 使用.NET .Substring()方法
  • 使用 array slicing,即将字串视为字符数组,以从和撷取子数组
  • 通过-replace运算符使用regex运算
  • 以下是性能指标评测的结果,它们给予了 * 相对 * 性能的 * 粗略 * 感觉:
  • PowerShell中的性能测量并不是一门精确的科学,其结果取决于许多因素--尤其是主机硬件;低于平均值50次运行的基准测试可以获得更好的效果,而Factor列中反映的是 * 相对 * 性能(1.00反映了最快的时间,所有其他值都是它的倍数)。
  • 1,000字符串执行(最多)20个字符的子串提取,其中一半字符串比1,000字符串长,一半字符串比1,000字符串短。
    *重要提示:基准测试将.Substring()调用的 * 有条件 * 解决方案与 * 无条件 * -replace和数组切片解决方案并列,这会使结果发生偏差-要比较真正的子字符串提取性能,后两种方法也需要修改为使用条件。
  • 只对.Substring()方法使用条件处理的原因是它是一种 * 必要性 *-为了避免例外-而其他方法的吸引力是 * 简洁 *,即 * 不 * 必须使用条件。
    性能指标评测结果
  • 在Windows 10机器上运行 Windows PowerShell v5.1的结果:
Factor Secs (50-run avg.) Command
------ ------------------ -------
1.00   0.001              # .Substring + if...
1.71   0.002              # .Substring + [math]::Min()...
5.24   0.006              # -replace + capture group...
8.32   0.010              # -replace + lookbehind...
160.84 0.198              # .Substring + try...
229.07 0.281              # array slicing + [string]::new()...
294.62 0.362              # array slicing + -join ...
  • 在同一台Windows 10计算机上运行 PowerShell(Core) 7.3.0的结果:
Factor Secs (50-run avg.) Command
------ ------------------ -------
1.00   0.002              # .Substring + ternary conditional…
1.09   0.002              # .Substring + if…
2.98   0.005              # .Substring + [math]::Min()…
3.79   0.006              # -replace + capture group…
6.64   0.011              # -replace + lookbehind…
132.11 0.215              # array slicing + [string]::new()…
160.99 0.262              # array slicing + -join …
163.68 0.266              # .Substring + try…

*摘要

  • 基于.Substring()的方法是迄今为止最快的--除非与try/catch结合使用(异常处理开销很大)。
  • v7+三元条件(? :)的执行方式与等效的if语句大致相同。
  • 基于-replace的解决方案在捕获组变体中的速度要慢3-5倍,大约是使用look-behindAssert的变体速度的两倍。
  • 到目前为止,最慢的是阵列切片方法和涉及try/catch的解决方案,速度慢了两个数量级。
    性能指标评测源代码
  • 要自己运行这些基准测试,您必须从this Gist下载函数Time-Command
  • 假设您已经查看了链接的Gist的源代码,以确保它是安全的(我个人可以向您保证,但您应该始终检查),您可以直接安装它如下:
irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
# Create 1000 strings, half of which longer than 20 chars., and half shorter.
$strs = , ('x' * 30) * 500 + , ('y' * 10) * 500

# Construct an array of script blocks with the various
# substring-extraction methods.
$cmds = 
{ # -replace + capture group
  foreach ($s in $strs) {
    $s -replace '^(.{20}).+', '$1'
  }
}, 
{ # -replace + lookbehind
  foreach ($s in $strs) {
    $s -replace '(?<=^.{20}).+'
  }
},
{ # .Substring + try
  foreach ($s in $strs) {
    try { $s.Substring(0, 20) } catch { $_}
  }
},
{ # .Substring + if
  foreach ($s in $strs) {
    if ($s.Length -gt 20) { $s.Substring(0, 20) } else { $s }
  }
},
{ # .Substring + [math]::Min()
  foreach ($s in $strs) {
    $s.Substring(0, [Math]::Min($s.Length, 20))
  }
},
{ # array slicing + -join 
  foreach ($s in $strs) {
    -join $s[0..19]
  }
},
{ # array slicing + [string]::new()
  foreach ($s in $strs) {
    [string]::new($s[0..19])
  }
}

# PowerShell (Core): add variant with ternary conditional.
if ($IsCoreClr) {
  # Note: The script block must be constructed *as a string*,
  #       to avoid breaking the parsing stage of the script in Windows PowerShell.
  $cmds += [scriptblock]::Create(@'
  # .Substring + ternary conditional
  foreach ($s in $strs) {
    $s.Length -gt 20 ? $s.Substring(0, 20) : $s
  }  
'@)
}

# Compare the performance of various substring extraction methods,
# averaged over 50 runs.
Time-Command -Count 50 $cmds
xuo3flqw

xuo3flqw2#

我个人会将索引运算符[ ]与范围运算符..结合使用:

Import-Csv "C:\\Users\\X\\Desktop\\U\\cvv.csv" | ForEach-Object {
    $_.A = [string]::new($_.A[0..19]).ToLower() # Update the the `A` value
    $_ # Output the object
} | Export-Csv -Path "C:\\Users\\X\\Desktop\\U\\cvv2.csv"

它将处理小于或大于所需长度的字符串:

PS /> 'HELLO WORLD', 'ONLY 20 CHARS LENGTH ALLOWED' | ForEach-Object {
    [string]::new($_[0..19]).ToLower()
}

hello world
only 20 chars length

相关问题