【问题标题】:Java, split a String by various tags and store it into a MapJava,通过各种标签拆分String并将其存储到Map中
【发布时间】:2016-01-04 11:07:51
【问题描述】:

我有一个要求,创建一种降价标签以在创建PDF's 时将 bold [N]italic [C] 文本放入给定的字符串中IText.

所以,给定这个字符串:

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

应该结果:

示例粗体文本其他示例斜体文本


好吧,我们走吧:

我有一个字体类型的枚举:

private enum FontType {
    BOLD, ITALIC, NORMAL
}

为了实现这一点,我想创建一个LinkedHashMap<String, Enum> 来插入具有相应字体类型的字符串片段(稍后将转换为com.itextpdf.text.Chunk 并插入单个com.itextpdf.text.Paragraph

那么我怎样才能达到这样的LinkedHashMap结果呢??

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

我创建了一个自定义的Iterator,它为我提供了标签位置:

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();
    }

}

我已经检查了标签是否平衡,我可以得到所有标签位置:

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

但是在得到所有位置后无法弄清楚如何区分每个部分并分配正确的枚举值。

一些想法? 也许我的方法有误,或者有人可以看到更好的方法?

【问题讨论】:

  • 你有没有想过使用正则表达式组?以javamex.com/tutorials/regular_expressions/… 为例。
  • @RatshiḓahoWayne 如果你看一下迭代器,正则表达式已经被使用了......你的意思是另一种方式?我使用正则表达式很糟糕:$
  • Regex 太复杂了,请看我贴出来的答案

标签: java regex dictionary split itext


【解决方案1】:

下面这段代码会给你想要的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;
}

但是当你发现两个或多个相等的字符串必须被散列时就会出现问题。

【讨论】:

  • 不错!当字符串以标签开头时出现错误......但非常感谢...... :)
  • 是的...抱歉,我已经修改了代码以使其即使在字符串以标签开头时也能正常工作。
  • 嗨@Ratsi,请检查答案中的更新,当缺少某些标签时,indexToUse 还存在一些其他问题。干杯
【解决方案2】:

这个怎么样?

...
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;
}

免责声明:这是未经编译的代码,因此未经测试。您将希望在 finally 块中处理异常并正确关闭您的资源(或使用 try-with-resources)。

【讨论】:

  • 对不起,但这个答案完全忽略了我的问题,正如我所说,我使用 iText 因此 &lt;b&gt;&lt;/b&gt; 和其他格式标签在这种情况下没有帮助。如果是这样,我只需要教用户使用 HTML 标签,不幸的是这不是一个选项,因为在 iText 中不起作用。
  • 我的答案使用com.itextpdf.text.html.simpleparser.HTMLWorker 并利用现有的基于 HTML 的文本标记支持。您可能不想这样做,但我认为它有效并且比您目前所拥有的要简单得多。
  • 好吧...HTMLWorker 已弃用,XMLWorker 项目不是免费的,AND 据我检查,不能应用于单个段落,我是能够使用 HTML 字符串创建格式化的 PDF,但我不能将其应用于单个文件,因此我应该将所有 PDF 创建(单元格、段落等)更改为 HTML 格式的 PDF.... 这似乎不是一个好的选择(太多时间)......
  • XMLWorker 是免费的,只要您遵守 AGPL 的条款。
猜你喜欢
  • 1970-01-01
  • 2017-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-22
相关资源
最近更新 更多