java - अपाचे POI XWPF में एक पाठ की जगह




ms-word apache-poi (6)

मुझे सिर्फ Apache POI लाइब्रेरी मिली है जो जावा का उपयोग करके वर्ड फाइल्स को एडिट करने के लिए बहुत उपयोगी है। विशेष रूप से, मैं Apache POI के XWPF वर्गों का उपयोग करके एक DOCX फ़ाइल संपादित करना चाहता हूं। मुझे कोई उचित विधि / दस्तावेज नहीं मिला जिसके बाद मैं ऐसा कर सका। क्या कोई कृपया चरणों में समझा सकता है, कैसे एक DOCX फ़ाइल में कुछ पाठ को बदलना है।

** पाठ एक पंक्ति / अनुच्छेद या एक तालिका पंक्ति / स्तंभ में हो सकता है

अग्रिम में धन्यवाद :)


कोड का पहला हिस्सा मुझे NullPointerException के साथ जोड़ रहा है, किसी को भी पता है कि क्या गलत है?

run.getText (int position) - प्रलेखन से: रिटर्न: इस पाठ का पाठ रन या शून्य यदि सेट नहीं है

बस जाँच करें कि क्या यह कॉल करने से पहले अशक्त नहीं है () है

और btw अगर आप पाठ को बदलना चाहते हैं तो आपको इसे उस स्थिति में सेट करने की ज़रूरत है जिससे आप इसे प्राप्त करते हैं, इस मामले में r.setText (पाठ, 0) ;; अन्यथा पाठ जोड़ा जाएगा प्रतिस्थापित नहीं


आपको जिस विधि की आवश्यकता है वह XWPFRun.setText(String) । बस फ़ाइल के माध्यम से अपना रास्ता तब तक काम करें जब तक आपको ब्याज का एक्सडब्ल्यूपीएफआर नहीं मिल जाता है, तब तक काम करें जो आप चाहते हैं कि नया पाठ हो और इसे प्रतिस्थापित करें। (एक रन एक ही स्वरूपण के साथ पाठ का एक क्रम है)

आपको कुछ ऐसा करने में सक्षम होना चाहिए:

XWPFDocument doc = new XWPFDocument(OPCPackage.open("input.docx"));
for (XWPFParagraph p : doc.getParagraphs()) {
    List<XWPFRun> runs = p.getRuns();
    if (runs != null) {
        for (XWPFRun r : runs) {
            String text = r.getText(0);
            if (text != null && text.contains("needle")) {
                text = text.replace("needle", "haystack");
                r.setText(text, 0);
            }
        }
    }
}
for (XWPFTable tbl : doc.getTables()) {
   for (XWPFTableRow row : tbl.getRows()) {
      for (XWPFTableCell cell : row.getTableCells()) {
         for (XWPFParagraph p : cell.getParagraphs()) {
            for (XWPFRun r : p.getRuns()) {
              String text = r.getText(0);
              if (text != null && text.contains("needle")) {
                text = text.replace("needle", "haystack");
                r.setText(text,0);
              }
            }
         }
      }
   }
}
doc.write(new FileOutputStream("output.docx"));

मैं # के बीच पाठ को बदलने के लिए अपना समाधान सुझाता हूं, उदाहरण के लिए: इस # बुकमार्क # को प्रतिस्थापित किया जाना चाहिए। इसमें प्रतिस्थापित है:

  • पैराग्राफ;
  • टेबल;
  • पाद।

इसके अलावा, यह उन स्थितियों को ध्यान में रखता है, जब प्रतीक # और बुकमार्क अलग-अलग रन में होते हैं (अलग-अलग रन के बीच परिवर्तनशील )।

यहाँ कोड से लिंक करें: https://gist.github.com/aerobium/bf02e443c079c5caec7568e167849dda


यदि किसी को पाठ का प्रारूपण रखने की आवश्यकता है, तो यह कोड बेहतर काम करता है।

private static Map<Integer, XWPFRun> getPosToRuns(XWPFParagraph paragraph) {
    int pos = 0;
    Map<Integer, XWPFRun> map = new HashMap<Integer, XWPFRun>(10);
    for (XWPFRun run : paragraph.getRuns()) {
        String runText = run.text();
        if (runText != null) {
            for (int i = 0; i < runText.length(); i++) {
                map.put(pos + i, run);
            }
            pos += runText.length();
        }
    }
    return (map);
}

public static <V> void replace(XWPFDocument document, Map<String, V> map) {
    List<XWPFParagraph> paragraphs = document.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
        replace(paragraph, map);
    }
}

public static <V> void replace(XWPFDocument document, String searchText, V replacement) {
    List<XWPFParagraph> paragraphs = document.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
        replace(paragraph, searchText, replacement);
    }
}

private static <V> void replace(XWPFParagraph paragraph, Map<String, V> map) {
    for (Map.Entry<String, V> entry : map.entrySet()) {
        replace(paragraph, entry.getKey(), entry.getValue());
    }
}

public static <V> void replace(XWPFParagraph paragraph, String searchText, V replacement) {
    boolean found = true;
    while (found) {
        found = false;
        int pos = paragraph.getText().indexOf(searchText);
        if (pos >= 0) {
            found = true;
            Map<Integer, XWPFRun> posToRuns = getPosToRuns(paragraph);
            XWPFRun run = posToRuns.get(pos);
            XWPFRun lastRun = posToRuns.get(pos + searchText.length() - 1);
            int runNum = paragraph.getRuns().indexOf(run);
            int lastRunNum = paragraph.getRuns().indexOf(lastRun);
            String texts[] = replacement.toString().split("\n");
            run.setText(texts[0], 0);
            XWPFRun newRun = run;
            for (int i = 1; i < texts.length; i++) {
                newRun.addCarriageReturn();
                newRun = paragraph.insertNewRun(runNum + i);
                /*
                    We should copy all style attributes
                    to the newRun from run
                    also from background color, ...
                    Here we duplicate only the simple attributes...
                 */
                newRun.setText(texts[i]);
                newRun.setBold(run.isBold());
                newRun.setCapitalized(run.isCapitalized());
                // newRun.setCharacterSpacing(run.getCharacterSpacing());
                newRun.setColor(run.getColor());
                newRun.setDoubleStrikethrough(run.isDoubleStrikeThrough());
                newRun.setEmbossed(run.isEmbossed());
                newRun.setFontFamily(run.getFontFamily());
                newRun.setFontSize(run.getFontSize());
                newRun.setImprinted(run.isImprinted());
                newRun.setItalic(run.isItalic());
                newRun.setKerning(run.getKerning());
                newRun.setShadow(run.isShadowed());
                newRun.setSmallCaps(run.isSmallCaps());
                newRun.setStrikeThrough(run.isStrikeThrough());
                newRun.setSubscript(run.getSubscript());
                newRun.setUnderline(run.getUnderline());
            }
            for (int i = lastRunNum + texts.length - 1; i > runNum + texts.length - 1; i--) {
                paragraph.removeRun(i);
            }
        }
    }
}

यहां स्वीकार किए गए उत्तर को जस्टिन स्काइल्स अपडेट के साथ एक और अपडेट की आवश्यकता है। r.setText (पाठ, 0); कारण: यदि पोज़ वेरिएबल के साथ सेटटेक्स्ट को अपडेट नहीं किया जा रहा है, तो आउटपुट पुराने स्ट्रिंग का संयोजन होगा और स्ट्रिंग को बदल देगा।


लेखन की तारीख तक, कोई भी उत्तर ठीक से नहीं बदलता है।

गगरवार जवाब में ऐसे मामले शामिल नहीं हैं जहां शब्दों को बदलने के लिए रन में विभाजित किया गया है; Thierry Boduins समाधान कभी-कभी शब्दों को खाली करने के लिए छोड़ देता है जब वे दूसरे शब्दों को बदलने के लिए होते हैं, तो यह तालिकाओं की जांच नहीं करता है।

आधार के रूप में गगतावारों के उत्तर का उपयोग करते हुए मैंने वर्तमान रन से पहले रन की भी जांच की है यदि दोनों रनों के पाठ में शब्द को बदलने के लिए शब्द है, जो ब्लॉक को जोड़ता है। कोटलिन में मेरा जोड़:

if (text != null) {
        if (text.contains(findText)) {
            text = text.replace(findText, replaceText)
            r.setText(text, 0)
        } else if (i > 0 && p.runs[i - 1].getText(0).plus(text).contains(findText)) {
            val pos = p.runs[i - 1].getText(0).indexOf('$')
            text = textOfNotFullSecondRun(text, findText)
            r.setText(text, 0)
            val findTextLengthInFirstRun = findTextPartInFirstRun(p.runs[i - 1].getText(0), findText)
            val prevRunText = p.runs[i - 1].getText(0).replaceRange(pos, findTextLengthInFirstRun, replaceText)
            p.runs[i - 1].setText(prevRunText, 0)
        }
    }

private fun textOfNotFullSecondRun(text: String, findText: String): String {
    return if (!text.contains(findText)) {
        textOfNotFullSecondRun(text, findText.drop(1))
    } else {
        text.replace(findText, "")
    }
}

private fun findTextPartInFirstRun(text: String, findText: String): Int {
    return if (text.contains(findText)) {
        findText.length
    } else {
        findTextPartInFirstRun(text, findText.dropLast(1))
    }
}

यह पैराग्राफ में रनों की सूची है। तालिका में खोज ब्लॉक के साथ भी। इस समाधान के साथ मेरे पास अभी तक कोई मुद्दा नहीं था। सभी स्वरूपण बरकरार है।

संपादित करें: मैंने प्रतिस्थापित करने के लिए एक java lib बनाया, इसे https://github.com/deividasstr/docx-word-replacer : https://github.com/deividasstr/docx-word-replacer







xwpf