Text in PDF-Dateien programmatisch mit C# suchen und ersetzen. Direkte Content-Stream-Bearbeitung — keine Konvertierung in DOCX, keine externen Abhaengigkeiten, kein Datenverlust.
dotnet add package Exis.PdfEditor
Install-Package Exis.PdfEditor
Die meisten .NET PDF-Bibliotheken — IronPDF, Spire.PDF, Aspose, Syncfusion — ersetzen Text, indem sie das PDF in ein Zwischenformat konvertieren, Text schwärzen und neuen Text darüber zeichnen, oder Seiten von Grund auf neu aufbauen.
Dieser Ansatz beschaedigt:
Exis.PdfEditor analysiert PDF-Content-Streams direkt auf Byte-Ebene. Es lokalisiert Text in den tatsaechlichen PDF-Operatoren, aendert nur die gezielten String-Operanden und schreibt mittels inkrementeller PDF-Aktualisierung zurueck.
Alles, was nicht beruehrt wird, bleibt Byte fuer Byte identisch:
using Exis.PdfEditor;
using Exis.PdfEditor.Licensing;
ExisLicense.Initialize(); // Free 14-day trial - no key needed
var result = PdfFindReplace.Execute(
"contract.pdf",
"contract-updated.pdf",
"Acme Corporation",
"Globex Industries");
Console.WriteLine($"Replaced {result.TotalReplacements} occurrences " +
$"across {result.PagesModified} pages.");
var pairs = new[]
{
new FindReplacePair("2025", "2026"),
new FindReplacePair("Draft", "Final"),
new FindReplacePair("CONFIDENTIAL", "PUBLIC"),
};
var result = PdfFindReplace.Execute(
"report.pdf",
"report-final.pdf",
pairs);
var options = new PdfFindReplaceOptions { UseRegex = true };
// Replace all US phone numbers with a placeholder
var result = PdfFindReplace.Execute(
"document.pdf",
"redacted.pdf",
@"\(\d{3}\)\s?\d{3}-\d{4}",
"[PHONE REDACTED]",
options);
// Purchase at officefindreplace.com/Home/pdf-find-replace-csharp - $499/developer/year
ExisLicense.Initialize("XXXX-XXXX-XXXX-XXXX");
// Unlimited pages, no restrictions, no console messages
var result = PdfFindReplace.Execute("large-doc.pdf", "output.pdf", "old", "new");
var options = new PdfFindReplaceOptions
{
CaseSensitive = true,
WholeWordOnly = false,
UseRegex = false,
UseIncrementalUpdate = true,
TextFitting = TextFittingMode.Adaptive, // Best quality text fitting
MinHorizontalScale = 70, // Minimum Tz percentage (50-100)
MaxFontSizeReduction = 1.5 // Max font size reduction in points
};
var result = PdfFindReplace.Execute(
"contract.pdf", "updated.pdf",
"Short Name", "A Much Longer Replacement Name That Needs Fitting",
options);
// Color replacement text and add a highlight background
var result = PdfFindReplace.Execute(
"input.pdf", "output.pdf",
"old text", "new text",
new PdfFindReplaceOptions
{
ReplacementTextColor = PdfColor.Red, // Font color of replaced text
ReplacementHighlightColor = PdfColor.Yellow // Background highlight behind text
});
// Merge multiple PDFs into one, preserving page dimensions and resources
byte[] merged = PdfMerger.Merge(new[] { "cover.pdf", "report.pdf", "appendix.pdf" });
File.WriteAllBytes("combined.pdf", merged);
// Or write directly to a file
PdfMerger.MergeToFile(new[] { "file1.pdf", "file2.pdf" }, "merged.pdf");
// Merge with page range selection
byte[] selected = PdfMerger.Merge(new[]
{
new PdfMergeInput(File.ReadAllBytes("doc1.pdf"), new[] { 1, 3, 5 }),
new PdfMergeInput(File.ReadAllBytes("doc2.pdf")) // all pages
});
// Split into individual pages
List<byte[]> pages = PdfSplitter.Split("input.pdf");
// Extract specific pages (1-based)
byte[] subset = PdfSplitter.ExtractPages("input.pdf", new[] { 1, 3, 5 });
// Split to individual files with naming pattern
PdfSplitter.SplitToFiles("input.pdf", "page_{0}.pdf");
byte[] pdf = PdfBuilder.Create()
.WithMetadata(m => m.Title("Report").Author("Exis"))
.AddPage(page => page
.Size(PdfPageSize.A4)
.AddText("Hello, World!", x: 72, y: 750, fontSize: 24,
options: o => o.Font("Helvetica").Bold().Color(0, 0, 0.8))
.AddText("Generated with Exis.PdfEditor", x: 72, y: 720, fontSize: 12)
.AddLine(72, 710, 523, 710, strokeWidth: 1)
.AddRectangle(72, 600, 200, 80, fill: true,
fillRed: 0.95, fillGreen: 0.95, fillBlue: 1.0)
.AddImage(jpegBytes, x: 300, y: 400, width: 200, height: 150))
.AddPage(page => page
.Size(PdfPageSize.Letter)
.AddText("Page 2", x: 72, y: 700, fontSize: 14))
.Build();
File.WriteAllBytes("output.pdf", pdf);
// Extract all text from a PDF
PdfTextResult text = PdfTextExtractor.ExtractText("input.pdf");
Console.WriteLine(text.FullText);
// Extract from specific pages only
PdfTextResult partial = PdfTextExtractor.ExtractText("input.pdf", new[] { 1, 3 });
// Structured extraction with position and font data
PdfStructuredTextResult structured = PdfTextExtractor.ExtractStructured("input.pdf");
foreach (var block in structured.Pages[0].TextBlocks)
Console.WriteLine($"[{block.X:F0},{block.Y:F0}] {block.Text} " +
$"(font={block.FontName}, size={block.FontSize})");
PdfDocumentInfo info = PdfInspector.Inspect("input.pdf");
Console.WriteLine($"Pages: {info.PageCount}");
Console.WriteLine($"Title: {info.Title}");
Console.WriteLine($"Fonts: {string.Join(", ", info.FontsUsed)}");
Console.WriteLine($"Encrypted: {info.IsEncrypted}");
Console.WriteLine($"Form fields: {info.FormFieldCount}");
// Find all images in a PDF
var found = PdfImageEditor.FindImages("input.pdf");
foreach (var img in found.Images)
Console.WriteLine($"Image #{img.Index}: {img.PixelWidth}x{img.PixelHeight} " +
$"{img.ColorSpace} {img.Format} on page(s) {string.Join(", ", img.PageNumbers)}");
// Replace all images with a new one
byte[] newLogo = File.ReadAllBytes("new-logo.jpg");
var result = PdfImageEditor.ReplaceAll("input.pdf", "output.pdf", newLogo);
Console.WriteLine($"Replaced {result.ImagesReplaced} of {result.ImagesFound} images");
// Replace specific images by index or page range
var selective = PdfImageEditor.Replace("input.pdf", "output.pdf", newLogo,
new PdfImageReplaceOptions { ImageIndices = new[] { 0, 2 } });
byte[] pdf = PdfDocumentBuilder.Create()
.PageSize(PdfPageSize.A4)
.Margins(72)
.WithMetadata(m => m.Title("Report").Author("Exis"))
.Header(h => h
.AddText("Quarterly Report", PdfHorizontalAlignment.Center, 12, o => o.Bold())
.AddLine())
.Footer(f => f
.AddLine()
.AddPageNumber()) // "Page 1 of 3"
.AddParagraph("Introduction", 18, o => o.Bold())
.AddSpacing(8)
.AddParagraph("This report covers Q1 results.")
.AddSpacing(12)
.AddTable(t => t
.Columns(2, 1, 1)
.AlternatingRowBackground(0.95, 0.95, 1.0)
.HeaderRow(r => r.AddCell("Product").AddCell("Units").AddCell("Revenue"))
.AddRow(r => r.AddCell("Widget A").AddCell("1,200").AddCell("$24,000"))
.AddRow(r => r.AddCell("Widget B").AddCell("850").AddCell("$17,000")))
.AddPageBreak()
.AddParagraph("Appendix", 14, o => o.Bold())
.Build();
// Read form fields
List<PdfFormField> fields = PdfFormFiller.GetFields("form.pdf");
foreach (var field in fields)
Console.WriteLine($"{field.Name} ({field.FieldType}) = {field.CurrentValue}");
// Fill fields
var result = PdfFormFiller.Fill("form.pdf", "filled.pdf", new Dictionary<string, string>
{
{ "FirstName", "John" },
{ "LastName", "Doe" },
{ "State", "CA" },
{ "AgreeToTerms", "Yes" } // checkbox
});
Console.WriteLine($"Filled {result.FieldsFilled} fields");
// Flatten form (merge field appearances, remove interactive fields)
PdfFormFiller.Flatten("filled.pdf", "flattened.pdf");
var result = PdfRedactor.Redact("input.pdf", "redacted.pdf", new[]
{
// Text-based redaction
new PdfRedaction { Text = "CONFIDENTIAL" },
// Regex pattern (e.g., SSN)
new PdfRedaction { Text = @"\d{3}-\d{2}-\d{4}", IsRegex = true },
// Replace with alternative text
new PdfRedaction { Text = "SECRET", ReplaceWith = "[REDACTED]" },
// Area-based redaction on specific page
new PdfRedaction { PageNumber = 3, Area = new PdfRect(100, 200, 300, 50) }
});
Console.WriteLine($"Applied {result.RedactionsApplied} redactions");
var result = PdfOptimizer.Optimize("input.pdf", "optimized.pdf", new PdfOptimizeOptions
{
CompressStreams = true,
RemoveDuplicateObjects = true,
RemoveMetadata = false,
DownsampleImages = true,
MaxImageDpi = 150
});
Console.WriteLine($"Saved {result.BytesSaved} bytes ({result.ReductionPercent:F1}%)");
Console.WriteLine($"Images downsampled: {result.ImagesDownsampled}");
using System.Security.Cryptography.X509Certificates;
// Sign a PDF
var cert = new X509Certificate2("certificate.pfx", "password");
PdfSigner.Sign("input.pdf", "signed.pdf", new PdfSignOptions
{
Certificate = cert,
Reason = "Approved",
Location = "New York",
ContactInfo = "admin@example.com"
});
// Verify a signed PDF
PdfSignatureInfo info = PdfSigner.Verify("signed.pdf");
Console.WriteLine($"Signed: {info.IsSigned}");
Console.WriteLine($"Valid: {info.IsValid}");
Console.WriteLine($"Signer: {info.SignerName}");
Console.WriteLine($"Certificate: {info.CertificateSubject}");
Console.WriteLine($"Issuer: {info.CertificateIssuer}");
Console.WriteLine($"Timestamp: {info.HasTimestamp}");
// Verify all signatures in a multi-signed document
List<PdfSignatureInfo> all = PdfSigner.VerifyAll("multi-signed.pdf");
foreach (var sig in all)
Console.WriteLine($"{sig.SignerName}: valid={sig.IsValid}");
// Validate (no license required)
// Levels: PdfA1b, PdfA2b, PdfA2u, PdfA3b, PdfA3u
PdfAValidationResult result = PdfAConverter.Validate("input.pdf", PdfALevel.PdfA2b);
Console.WriteLine($"Compliant: {result.IsCompliant}");
foreach (var v in result.Violations)
Console.WriteLine($" [{v.Code}] {v.Message} (auto-fix: {v.CanAutoFix})");
// Convert to PDF/A
byte[] pdfa = PdfAConverter.Convert("input.pdf", PdfALevel.PdfA2b);
File.WriteAllBytes("output-pdfa.pdf", pdfa);
// All I/O operations have async overloads with CancellationToken support
byte[] merged = await PdfMerger.MergeAsync(inputPaths, cancellationToken);
PdfTextResult text = await PdfTextExtractor.ExtractTextAsync(stream, cancellationToken);
var info = await PdfInspector.InspectAsync(path, cancellationToken);
var result = await PdfOptimizer.OptimizeAsync(data, options, cancellationToken);
var sigs = await PdfSigner.VerifyAllAsync(path, cancellationToken);
// Pattern: ClassName.MethodNameAsync(...) on all classes
| Funktion | Exis.PdfEditor | IronPDF | Spire.PDF | Aspose.PDF | Syncfusion |
|---|---|---|---|---|---|
| Direkte Content-Stream-Bearbeitung | ✓ | ✗ Rendert HTML | ✗ Schwärzungs-Overlay | ✗ Fragment-Ersetzung | ✗ Schwärzungs-Overlay |
| Erhaelt Formularfelder | ✓ | ✗ | Teilweise | Teilweise | ✗ |
| Erhaelt digitale Signaturen | ✓ Nicht modifizierte Seiten | ✗ | ✗ | ✗ | ✗ |
| Erhaelt Textabstand/Kerning | ✓ | ✗ | ✗ | Teilweise | ✗ |
| Null native Abhaengigkeiten | ✓ Reines .NET | ✗ Chromium-Engine | ✓ | ✓ | ✓ |
| DLL-Groesse | < 500 KB | ~250 MB | ~20 MB | ~40 MB | ~15 MB |
| Batch-Ersetzung mehrerer Paare | ✓ Einzeldurchlauf | Manuelle Schleife | Manuelle Schleife | Manuelle Schleife | Manuelle Schleife |
| .NET Framework 4.8 | ✓ | ✓ | ✓ | ✓ | ✗ Nur .NET 6+ |
| Plattformuebergreifend | ✓ | ✓ | ✓ | ✓ | ✓ |
| Regex-Unterstuetzung | ✓ | ✓ | ✓ | ✓ | ✓ |
| Preis (pro Entwickler/Jahr) | $499 | $749 | $999 | $1,175 | $995* |
| Firmensitz | 🇺🇸 USA | 🇺🇸 USA | 🇨🇳 China | 🇦🇺 Australia | 🇺🇸 USA |
Vergleich basiert auf oeffentlich verfuegbarer Dokumentation, Stand Februar 2026. Funktionsunterstuetzung kann je nach Version variieren.
"Direkte Content-Stream-Bearbeitung" bedeutet, dass die Bibliothek PDF-Textoperatoren direkt aendert, ohne zu konvertieren, neu zu rendern oder zu ueberlagern.
Aendert Content-Stream-Operatoren. Keine Zwischenkonvertierung.
Kein Ghostscript, kein LibreOffice, kein Chromium. Reines verwaltetes .NET.
Formulare, Signaturen, Anmerkungen, Lesezeichen — alles erhalten.
.NET 8, 9, 10+ und .NET Standard 2.0 (.NET Framework 4.6.1+, .NET Core 2.0+, .NET 5-7).
Mehrere Suchen/Ersetzen-Paare in einem einzigen Durchlauf ausgefuehrt.
Volle .NET Regex-Unterstuetzung fuer musterbasierte Ersetzungen.
Windows, Linux, macOS. Ueberall wo .NET laeuft.
Einzelne DLL, unter 500 KB. Keine nativen Binaerdateien zu installieren.
Combine multiple PDFs into one document, preserving page dimensions and resources.
Extract individual pages or page ranges into separate PDFs. Split to files with naming patterns.
Create PDFs from scratch with a fluent API. Add text, images, lines, and rectangles with full formatting control.
Pull text content from PDF pages. Extract from all pages or specific page ranges.
Read metadata, fonts, page dimensions, and form field counts. Works without any license.
Find, analyze, and replace images in PDFs. Swap logos or graphics by index or page range with JPEG/PNG.
Create reports with auto-pagination, text wrapping, tables, headers/footers, and page numbers.
Read and fill AcroForm fields including text, checkbox, and dropdown. Lossless form preservation.
Text-based, regex pattern, or area-based redaction. Permanently remove sensitive content from PDFs.
Compress streams, remove duplicate objects, and reduce file size while preserving document quality.
Sign PDFs with X.509 certificates and verify existing signatures. Available on .NET 8, 9, 10+.
Validate and convert to PDF/A (1b, 2b, 2u, 3b, 3u) for long-term archival. Validation works without a license.
All I/O operations have async overloads with CancellationToken support for scalable applications.
Installieren Sie das NuGet-Paket und rufen Sie ExisLicense.Initialize() auf — volle Funktionalitaet fuer 14 Tage. Nach der Testversion verarbeitet der Evaluierungsmodus bis zu 3 Seiten pro Dokument. Keine Wasserzeichen. Wenn Sie bereit sind, kaufen Sie einen Lizenzschluessel auf officefindreplace.com/Home/pdf-find-replace-csharp.
Preise in US-Dollar. Ein Schluessel pro Entwickler. Funktioniert auf Entwicklungsrechner, Build-Server und Produktion — keine Begrenzung pro Maschine oder Bereitstellung.
Ihr Code aendert sich nicht zwischen Testmodus und lizenziertem Modus. Fuegen Sie einfach Ihren Schluessel hinzu, wenn Sie bereit sind.
dotnet add package Exis.PdfEditor
Fragen? E-Mail an support@exisone.com — Sie erhalten eine Antwort von einem Entwickler, nicht von einem Bot.