我已经对此进行了数周的研究,似乎在这个问题上没有太大的进展。我有一个很大的PDF(超过900页),这是邮件合并的结果。结果是同一文档的900多个副本(一页),唯一的不同是在底部有一个人的名字。我想做的是让Powershell脚本使用itextsharp读取文档,并将包含特定字符串(人名)的页面保存到各自的文件夹中。
这是我到目前为止所管理的。
Add-Type -Path C:\scripts\itextsharp.dll
$reader = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList
"$pwd\downloads\TMs.pdf"
for($page = 1; $page -le $reader.NumberOfPages; $page++) {
$pageText = [iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($reader,$page).Split([char]0x000A)
if($PageText -match 'DAN KAGAN'){
Write-Host "DAN FOUND"
}
}
如您所见,我现在仅使用一个名称进行测试。该脚本会正确找到该名称10次。我似乎找不到任何信息,是如何提取出现此字符串的页面。
我希望这很清楚。如果需要帮助,请告诉我。
谢谢!
答案 0 :(得分:4)
我实际上刚写完一个非常相似的脚本。使用我的脚本,我需要扫描报告卡的PDF,找到学生的姓名和ID号,然后提取该页面并适当命名。但是,每个报告卡可以跨越多个页面。
您似乎正在使用iTextSharp 5,这很好,因为我也是如此。iTextSharp7的语法有很大不同,我还没有学过。
以下是进行页面提取的逻辑:
$Document = [iTextSharp.text.Document]::new($PdfReader.GetPageSizeWithRotation($StartPage))
$TargetMemoryStream = [System.IO.MemoryStream]::new()
$PdfCopy = [iTextSharp.text.pdf.PdfSmartCopy]::new($Document, $TargetMemoryStream)
$Document.Open()
foreach ($Page in $StartPage..$EndPage) {
$PdfCopy.AddPage($PdfCopy.GetImportedPage($PdfReader, $Page));
}
$Document.Close()
$NewFileName = 'Elementary Student Record - {0}.pdf' -f $Current.Student_Id
$NewFileFullName = [System.IO.Path]::Combine($OutputFolder, $NewFileName)
[System.IO.File]::WriteAllBytes($NewFileFullName, $TargetMemoryStream.ToArray())
这是完整的工作脚本。我删除了尽可能少的内容,为您提供了一个可行的示例:
Import-Module -Name SqlServer -Cmdlet Invoke-Sqlcmd
Add-Type -Path 'C:\...\itextsharp.dll'
# Get table of valid student IDs
$ServerInstance = '...'
$Database = '...'
$Query = @'
select student_id, student_name from student
'@
$ValidStudents = @{}
Invoke-Sqlcmd -Query $Query -ServerInstance $ServerInstance -Database $Database -OutputAs DataRows | ForEach-Object {
[void]$ValidStudents.Add($_.student_id.trim(), $_.student_name)
}
$PdfFiles = Get-ChildItem "G:\....\*.pdf" -File |
Select-Object -ExpandProperty FullName
$OutputFolder = 'G:\...'
$StudentIDSearchPattern = '(?mn)^(?<Student_Id>\d{6,7}) - (?<Student_Name>.*)$'
foreach ($PdfFile in $PdfFiles) {
$PdfReader = [iTextSharp.text.pdf.PdfReader]::new($PdfFile)
$StudentStack = [System.Collections.Stack]::new()
# Map out the PDF file.
foreach ($Page in 1..($PdfReader.NumberOfPages)) {
[iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($PdfReader, $Page) |
Where-Object { $_ -match $StudentIDSearchPattern } |
ForEach-Object {
$StudentStack.Push([PSCustomObject]@{
Student_Id = $Matches['Student_Id']
Student_Name = $Matches['Student_Name']
StartPage = $Page
IsValid = $ValidStudents.ContainsKey($Matches['Student_Id'])
})
}
}
# Extract the pages and save the files
$LastPage = $PdfReader.NumberOfPages
while ($StudentStack.Count -gt 0) {
$Current = $StudentStack.Pop()
$StartPage = $Current.StartPage
$EndPage = $LastPage
$Document = [iTextSharp.text.Document]::new($PdfReader.GetPageSizeWithRotation($StartPage))
$TargetMemoryStream = [System.IO.MemoryStream]::new()
$PdfCopy = [iTextSharp.text.pdf.PdfSmartCopy]::new($Document, $TargetMemoryStream)
$Document.Open()
foreach ($Page in $StartPage..$EndPage) {
$PdfCopy.AddPage($PdfCopy.GetImportedPage($PdfReader, $Page));
}
$Document.Close()
$NewFileName = 'Elementary Student Record - {0}.pdf' -f $Current.Student_Id
$NewFileFullName = [System.IO.Path]::Combine($OutputFolder, $NewFileName)
[System.IO.File]::WriteAllBytes($NewFileFullName, $TargetMemoryStream.ToArray())
$LastPage = $Current.StartPage - 1
}
}
在我的测试环境中,这将在15秒钟内处理5个源PDF中的大约500名学生。
我倾向于使用构造函数而不是New-Object
,但是它们之间并没有真正的区别。我只是觉得它们更容易阅读。