我一直在努力解决我认为非常简单的问题,但我无法看到它。我有一堆30多个csv文件,每天由不同的应用程序生成不同的内容,我需要在导入到单个报告数据库之前进行规范化。提取,转换和加载(ETL)类型的东西 - 全局查找和替换。
循环浏览文件没问题 - 不确定使用ForEach-Object Fullname
是否是输出到' OUT'的最佳方式。文件夹搞砸了但是使用-Name
意味着我必须包含路径。
基本上,所有' True' False'文本将被替换为1/0,与' yes' /' no',poweredon / poweredoff等相同。此外,我们有4个站点 - 每个站点都需要替换为ref。 id,这样的东西。我已经尝试修改我在网上找到的大量脚本 - 很多都在这里。尝试使用数组中的替换文本,将CSV拉成字符串,只是无法看到它。我用VBScript多年来一直在做同样的事情,这很简单。但是我需要学习PowerShell,所以我要坚持下去。
答案 0 :(得分:1)
基本上,所有'True'/'False'文本都将替换为1/0,同样是'yes'/'no',poweredon / poweroff等。此外,我们有4个站点 - 每个站点需要替换为REF。 id,这样的东西。我已经尝试修改我在网上发现的大量脚本 - 很多都在这里。尝试使用数组中的替换文本,将csv拉入字符串,只是看不到它。多年来我一直用vbscript做同样的事情,这很简单。但我需要学习PShell,所以我要坚持下去。我真的很感激这里的一些帮助。
如果它是静态的,你可能会逃脱:
$changes = @{
'true' = '1';
'false' = '0';
'poweredon' = '1';
'poweredoff' = '0'
}
$folder = "" # your folder here
$csvFiles = ls $folder *.csv
foreach ($file in $csvFiles) {
$csvData = import-csv $file
foreach ($row in $csvData) {
$cells = $row | `
gm | `
?{$_.MemberType -eq 'NoteProperty'} | `
select -exp Name
foreach ( $cell in $cells ) {
$val = $row."$cell"
$valueNeedsChanging = $changes.ContainsKey($val)
if ( $valueNeedsChanging ) {
$newValue = $changes[$val]
$row."$cell" = $newValue
}
}
}
cp $file.FullName "$($file.FullName).bak" # back it up before saving
$csvData | export-csv -Path $file.FullName -NoTypeInformation
}
我选择使用Import-
和Export-CSV
为具有大量高级格式的文件保留CSV文件的结构。
答案 1 :(得分:0)
好的,这是一个快速搜索和替换功能。它可以读取多个CSV文件并匹配\替换多个值。
function Replace-CsvValue
{
[CmdletBinding()] # Enable pipeline support
Param
(
# Filename, mandatory, takes pipeline input
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
# Alias, allows to directly pipe Get-ChildItem output to this function
[Alias('FullName')]
[string]$File,
# Scriptblock, mandatory, does actual search and replace
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[scriptblock]$ScriptBlock
)
Process
{
# Import CSV
$CsvFile = $File | Import-Csv
# Generate new filename
$NewFileName = Join-Path -Path (Split-Path -Path $File -Parent) -ChildPath ('Processed_' + (Split-Path -Path $File -Leaf))
# Iterate over each line in CSV
$CsvFile | ForEach-Object {
# Execute scritblock against record
& $ScriptBlock
}
# Export CSV
$CsvFile | Export-Csv -Path $NewFileName -NoTypeInformation
}
}
Get-ChildItem
输出到函数并传递scriptblock 原始CSV文件:
State, Active, Available
PoweredOn, True, Yes
函数调用:
# Scriptblock with replace logic
$ReplaceRule = {
# Iterate over each item in CSV line
$Item = $_
$_.PSObject.Properties.Name | ForEach-Object {
# If item name matches...
switch ($_)
{
'State' {
# If item value matches...
if($Item.$_ -eq 'PoweredOn')
{
$Item.$_ = 'Online'
}
# Or if item value matches...
elseif($Item.$_ -eq 'PoweredOff')
{
$Item.$_ = 'Offline'
}
break
}
# More replace rules, you can add your own here...
'Active' {
if($Item.$_ -eq 'True')
{
$Item.$_ = '1'
}
elseif($Item.$_ -eq 'False')
{
$Item.$_ = '0'
}
break
}
'Available' {
if($Item.$_ -eq 'Yes')
{
$Item.$_ = '1'
}
elseif($Item.$_ -eq 'No')
{
$Item.$_ = '0'
}
break
}
}
}
}
# Get all CSV files that match wildcard and
# feed them to the Replace-CsvValue function
Get-ChildItem -Path '.\' -Filter '*Report*.csv' | Replace-CsvValue -ScriptBlock $ReplaceRule
已处理的CSV文件:
"State","Active","Available"
"Online","1","1"
答案 2 :(得分:0)
我在in android.R.drawable
的帮助下制作了这个用于测试的csv。请注意,某人的名字是True。我在那里检查以确保我的逻辑正常。
Present Name Lunch State
------- ---- ----- -----
TRUE Jesse Daniels No Powered Off
FALSE Debra Cunningham Yes Powered Off
TRUE True Jones Yes Powered Off
TRUE George Fernandez Yes Powered Off
FALSE Lisa Cox No Powered On
出于这个目的,我认为忽略它是一个CSV并且只是直接替换文本这一事实很简单。我们必须小心的警告是部分匹配。使用正则表达式我们应该能够解释这种可能性。
您已经知道可以链接-replace
的评论。让我们在那里添加一些正则表达式魔法,以使过程更容易。
$filename = "C:\temp\MOCK_DATA.csv"
$oneKeywordPattern = "Powered On","Yes","True" -join "|"
$zeroKeywordPattern = "Powered Off","No","False" -join "|"
(Get-Content $filename) -replace "(?<=^|,)$oneKeywordPattern(?=$|,)","1" -replace "(?<=^|,)$zeroKeywordPattern(?=$|,)","0" | Set-Content $filename
为了确保考虑csv结构,我们只在元素位于行的开头或逗号后面的行或逗号(这是使用Mockaroo)时替换。这也确保我们只更改完整元素,并且True Jones不受影响。
我们使用$oneKeywordPattern
,以便您可以向需要更改为1的数组添加元素。我们使用管道将它们连接起来,以便将其视为替代正则表达式模式。其对应$zeroKeywordPattern
的功能相同。
<强>输出强>
Present Name Lunch State
------- ---- ----- -----
1 Jesse Daniels 0 0
0 Debra Cunningham 1 0
1 True Jones 1 0
1 George Fernandez 1 0
0 Lisa Cox 0 1
您可能有其他模式不需要使用此逻辑进行更改。只需链接另一个-replace
并记住它支持正则表达式,所以要注意特殊字符。
这里的两个警告是,如果文件很大,可能需要一段时间来加载文件并处理正则表达式(特别是如果你添加更多。)此外,如果你的文字用引号括起来,我们目前不会考虑但这很容易。