Ich habe die Anforderung, eine Art Markdown-Tags zu erstellen, um beim Erstellen von {{X2 }} mit IText.

Also, angesichts dieser Zeichenfolge:

String toCheck = "Example [N]bold text[N] other example [C]italic text[C]";

Sollte ergeben:

Beispiel Fettdruck anderes Beispiel Kursivtext


Also, lasst uns gehen:

Ich habe eine Aufzählung mit Schriftarten:

private enum FontType {
    BOLD, ITALIC, NORMAL
}

Um dies zu erreichen, möchte ich ein LinkedHashMap<String, Enum> erstellen, um die String-Fragmente mit dem entsprechenden Schrifttyp einzufügen (letzteres wird in com.itextpdf.text.Chunk umgewandelt und in ein einzelnes com.itextpdf.text.Paragraph eingefügt.

Wie kann ich das LinkedHashMap Ergebnis so erzielen?

pos String            enum
0   "Example "        NORMAL
1   "bold text"       BOLD
2   " other example " NORMAL
3   "italic text"     ITALIC

Ich habe ein benutzerdefiniertes Iterator erstellt, das mir die Tag-Position gibt:

public class OwnIterator implements Iterator<Integer> 
{
    private Iterator<Integer> occurrencesItr;

    public OwnIterator(String toCheck, String[] validPair) {
        // build regex to search for every item in validPair
        Matcher[] matchValidPair = new Matcher[validPair.length];
        for (int i = 0 ; i < validPair.length ; i++) {
            String regex = 
                    "(" +    // start capturing group
                    "\\Q" +  // quote entire input string so it is not interpreted as regex
                    validPair[i] +  // this is what we are looking for, duhh 
                    "\\E" +  // end quote
                    ")" ;    // end capturing group
            Pattern p = Pattern.compile(regex);
            matchValidPair[i] = p.matcher(toCheck);
        }
        // do the search, saving found occurrences in list
        List<Integer> occurrences = new ArrayList<>();
        for (int i = 0 ; i < matchValidPair.length ; i++) {
            while (matchValidPair[i].find()) {
                occurrences.add(matchValidPair[i].start(0)+1);  // +1 if you want index to start at 1 
            }
        }
        // sort the list 
        Collections.sort(occurrences);
        occurrencesItr = occurrences.iterator();
    }

    @Override
    public boolean hasNext()  {
        return occurrencesItr.hasNext();
    }

    @Override
    public Integer next() {
        return occurrencesItr.next();
    }

    @Override
    public void remove() {
        occurrencesItr.remove();
    }

}

Ich habe bereits überprüft, ob Tags ausgeglichen sind, und kann alle Tag-Positionen abrufen:

String[] validPair = {"[N]", "[C]" };
OwnIterator itr = new OwnIterator(toCheck, validPair);
while (itr.hasNext()) {
    System.out.println(itr.next());
}

Aber nachdem Sie alle Positionen erhalten haben, können Sie nicht herausfinden, wie Sie jeden Teil unterscheiden und den richtigen Aufzählungswert zuweisen können.

Einige Ideen? Vielleicht irre ich mich oder jemand kann einen besseren sehen?

3
Jordi Castilla 4 Jän. 2016 im 14:07

2 Antworten

Beste Antwort

Der folgende Code gibt Ihnen das gewünschte LinkedHashMap,

private Map<String, FontType> getMapFromTags(String toCheck) {
    Map<String, FontType> chunksMap = new LinkedHashMap<>();
    boolean openTag = false;

    while (toCheck.contains(TAG_NEGRITA) || toCheck.contains(TAG_CURSIVA)) {
        final int indexOfBold = toCheck.indexOf(TAG_NEGRITA);
        final int indexOfItalics = toCheck.indexOf(TAG_CURSIVA);

        final int indexToUse = getValidIndexToUse(indexOfBold, indexOfItalics);

        final String substring = toCheck.substring(0, indexToUse);
        toCheck = toCheck.substring(indexToUse + 3, toCheck.length());

        if (!substring.isEmpty()) {
            if (!openTag) {
                chunksMap.put(substring, FontType.NORMAL);
            } else if (indexToUse == indexOfBold) {
                chunksMap.put(substring, FontType.BOLD);
            } else {
                chunksMap.put(substring, FontType.ITALIC);
            }
        }

        openTag = !openTag;
    }
    // check if there is some NORMAL text at the end
    if (!toCheck.isEmpty())
        chunksMap.put(toCheck, FontType.NORMAL);

    return chunksMap;
}

private int getValidIndexToUse(int indexOfBold, int indexOfItalics) {
    if (indexOfBold > -1 && indexOfItalics == -1)
        return indexOfBold;
    else if (indexOfItalics > -1 && indexOfBold == -1)
        return indexOfItalics;
    else 
        return indexOfBold > -1 && indexOfBold < indexOfItalics ? indexOfBold : indexOfItalics;
}

Es wird jedoch Probleme geben, wenn Sie zwei oder mehr gleiche Zeichenfolgen finden, die gehasht werden müssen.

2
Jordi Castilla 10 März 2016 im 11:12

Wie wäre es damit?

...
String toCheck = "Example [N]bold text[N] other example [C]italic text[C]";
toCheck = replacePairs(toCheck , "[N]","<b>", "</b>");
toCheck = replacePairs(toCheck , "[C]","<i>", "</i>");

OutputStream file = new FileOutputStream(new File("Test.pdf"));
Document document = new Document();
PdfWriter.getInstance(document, file);
document.open();
HTMLWorker htmlWorker = new HTMLWorker(document);
htmlWorker.parse(new StringReader(toCheck));
document.close();
file.close();
...

private String replacePairs(String input, String tag, String openTag, String closeTag) {
    String output = input;
    while(output.indexOf(tag) >= 0) {
        output = output.replaceFirst(tag, openTag);
        if (output.indexOf(tag) < 0) {
            throw new IllegalArgumentException("Missing closing tag:" + tag);
        }
        output = output.replaceFirst(tag, closeTag);
    }
    return output;
}

Haftungsausschluss: Dies ist nicht kompilierter und somit nicht getesteter Code. Sie sollten Ausnahmen behandeln und Ihre Ressourcen im finally-Block ordnungsgemäß schließen (oder Try-with-Resources verwenden).

0
Adriaan Koster 4 Jän. 2016 im 11:31