2017年6月1日 星期四

[PowerShell] [Office] 快速完成文字檔「搜尋取代」字串的工作

這張圖的設計者應該就是Developer,我也幾喜歡這張圖,但我畢竟不是IT (所以出來寫的code大概在專業眼中會看出奇怪,用的程式也雜亂)。在營運部門的工作中有時接到奇奇怪怪的問題和要求,應不應該做、如何做,都是要討論的問題。其中一個就算要做也是相關的技術部門比我們更適合處理的情況,就是一些批量處理資料庫數據的情況,最近就有個類似的情況。也許我應該也要多站在後面抱頭、蒙眼、尖叫⋯⋯

我們要手動處理的話是這樣的:現在有的是每月一個的txt檔,想將每個檔案的內容當中某個出現多次的日期字串全部換作該月1-31號 (共分別31個檔案),輸出成 每日一個的 txt 檔。之後拿到系統介面作上傳之用。

在討論上面提到的「應該」、「如何」的問題之餘,作為非IT人也想了想如何善用科技去更有效率地改善工序。這問題想起的是用 PowerShell,大概辦公室環境中,與Excel無關、檔案動作和 txt 文字處理,就會偏向 Batch 或 PowerShell 這類 script。在網路上循這個方向找找,重點部份其實只需要一句,pipe了幾個指令,便解決了問題。 那句例子:
(Get-Content test.txt) | ForEach-Object { $_ -replace "foo", "bar" } | Set-Content test2.txt


-- 1a. Single to Multiple-----
完整版本,上面的重點句子,加上 For-loop處理 1-31日的檔案 和一些前後的工序:
# input
$year = 2017
$month = 05
$lastDay = 31
$oldFile = 'FOO_May17.txt'
$oldString = '15/05/2017'

$ Start here
$newString = ''
$newFile = ''

For ($i=1; $i -le $lastDay; $i++) {
    $newString = $i.ToString("00") + '/' + $month.ToString("00") + '/' +  $year.ToString("0000")
    $newFile = 'FOO_' + $year.ToString("0000") + $month.ToString("00") + $i.ToString("00") + '.txt'
    (Get-Content -Path $oldFile).replace($oldString, $newString) | Set-Content -Path $newFile
}

-- 1b. Single to Single - no holiday-----
之後想到不如避開星期六日、上傳 1 個檔案比分開 2x 個檔案方便。加入了[Date].DayofWeek() 去分辨周未、Add-Content 代替 Set-Content 去 避免製作大量檔案:
# input
$year = 2017
$month = 05
$lastDay = 31
$oldFile = 'FOO_May17.txt'
$oldString = '15/05/2017'

$ Start here
$newString = ''
$newFile = 'FOO_' + $year.ToString("0000") + $month.ToString("00") + '.txt'

For ($i=1; $i -le $lastDay; $i++) {
  $newString = $i.ToString("00") + '/' + $month.ToString("00") + '/' +  $year.ToString("0000")
  if ( [Int]([datetime::ParseExact($newString,"dd/MM/yyyy",$null)).DayOfWeek % 6 -ne 0) {
    (Get-Content -Path $oldFile).replace($oldString, $newString) | Add-Content -Path $newFile
  }
}

-- 2. Combine txt-----
另一個方案是一個專門用來結合檔案的Script。(Out-File -NoClopper 是另一個可以做到類似Add-Conent 的方法,這裡分別不大。不過其他用途時可以知道編碼上Add-Content預設的是ASCII、Out-File預設的是Unicode,還有如果將console內容輸出時的 width 會否導致斷行的分別。)
# input
$directory = ".\temp\"
$resultFile = "FileCombined.txt"

Get-ChildItem -Path $directory -include *.txt -Recurse | Get-Content | Out-File -FilePath $resultFile - NoClobber

沒有留言:

張貼留言