I have a requirement, create a kind of markdown tags to put bold [N] and italic [C] text in a given string when creating PDF's with IText.
So, given this string:
String toCheck = "Example [N]bold text[N] other example [C]italic text[C]";
Should result:
Example bold text other example italic text
Well, let's go:
I have an enum with font types:
private enum FontType {
BOLD, ITALIC, NORMAL
}
To achieve that I want to create a LinkedHashMap<String, Enum> to insert the String fragments with the corresponding font type (this will be latter transformed to com.itextpdf.text.Chunk and inserted into a single com.itextpdf.text.Paragraph.
So how can I achieve the LinkedHashMap result like this??
pos String enum
0 "Example " NORMAL
1 "bold text" BOLD
2 " other example " NORMAL
3 "italic text" ITALIC
I created a custom Iterator that gives me the tag position:
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();
}
}
I already checked if tags are balanced, and I can get all tag positions:
String[] validPair = {"[N]", "[C]" };
OwnIterator itr = new OwnIterator(toCheck, validPair);
while (itr.hasNext()) {
System.out.println(itr.next());
}
But after getting all the positions can't figure out how to discriminate each portion and assign the correct enum value.
Some ideas? Maybe I'm wrong in my approach or someone can see a better one?
The following piece of code will give you the desired 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;
}
But there will be issues when you find two or more equal strings that has to be hashed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With