Java解析ADIF文件

标签 java parsing adif

ADIF 格式描述如下:http://www.adif.org/我正在尝试制作 Adif 解析器。以下是要解析的 Adif 文件的一部分:

ADIF 2 Export from eQSL.cc 
Received eQSLs for IZ1080SWL 
for QSOs between 10-Aug-2015 and 31-Dec-2035 
Generated on Sunday, October 18, 2015 at 00:48:50 AM UTC
<PROGRAMID:21>eQSL.cc DownloadInBox
<ADIF_Ver:1>2 
<EOH>
<CALL:6>RA1QEA<QSO_DATE:8:D>20150829<TIME_ON:4>0455<BAND:3>30m<MODE:2>CW<RST_SENT:3>SWL<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<APP_EQSL_AG:1>Y<GRIDSQUARE:6>lo19aq<EOR>
<CALL:5>F6HKA<QSO_DATE:8:D>20150910<TIME_ON:4>0400<BAND:3>80m<MODE:2>CW<RST_SENT:3>swl<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<QSLMSG:34>Thanks for the SWL report. 73 Bert<APP_EQSL_AG:1>Y<GRIDSQUARE:6>JN05ot<EOR>
<CALL:5>DL5ZL<QSO_DATE:8:D>20150912<TIME_ON:4>2229<BAND:3>30m<MODE:2>CW<RST_SENT:3>599<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<QSLMSG:28>tks, paper qsl is on the way<APP_EQSL_AG:1>Y<GRIDSQUARE:6>JO51jl<EOR>
<CALL:5>4Z5ML<QSO_DATE:8:D>20150915<TIME_ON:4>0504<BAND:3>20m<MODE:2>CW<RST_SENT:3>599<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<APP_EQSL_AG:1>Y<GRIDSQUARE:4>km72<EOR>

我尝试这个解析器:

    public void read() throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(filePath));

    int intValue;
    boolean createToken = false;
    boolean createSize = false;
    StringBuffer token = new StringBuffer();
    StringBuffer size = new StringBuffer();
    Adif2Record record = new Adif2Record();


    while ((intValue = br.read()) != -1) {
        char cValue = (char)intValue;

        if (cValue == '\n') {
            continue;
        }
        if (cValue == '<') {
            createToken = true;
            continue;
        }
        if (cValue == ':') {
            createToken = false;
            createSize = true;
            continue;
        }
        if (cValue == '>') {
            if ("eor".equalsIgnoreCase(token.toString())) {
                records.add(record);
                record = new Adif2Record();
                token.setLength(0);
                size.setLength(0);
                continue;
            }
            createSize = false;
            createData(br, token.toString(), str2int(size.toString()), record);
            size.setLength(0);
            token.setLength(0);

        }

        if (createToken) {
            token.append(cValue);
        }
        if (createSize) {
            size.append(cValue);
        }
    }

}

但我最终只得到一个 token “PROGRAMID”,文件的其余部分成为该 token 的数据。 EOF 标记之前的部分是 header ,我不想将其完全切片,但我不明白为什么 createSize 在 PROGRAMID 之后保持 true,根据想法,它应该在每次循环后重置为 false。有人可以帮忙吗?

最佳答案

您缺少处理 header 的逻辑。基本上, header 似乎允许包含包括 : 在内的文本,这意味着您必须添加一个检查,它正在将标签解析为您获得 : 字符的情况.

此外,您需要适本地处理数据类型,否则类型会简单地附加到大小。

此外,您应该使用 StringBuilder 而不是 StringBuffer,因为后者也会进行同步,在这种情况下只会降低性能,而不会带来任何好处。

以下代码还用 switch 语句替换了一些 if

为了简单起见,它使用另一条记录作为标题数据...

public static void createData(BufferedReader br, String token, int size, Adif2Record record) throws IOException {
    StringBuilder sb = new StringBuilder(size);
    for (int i = 0; i < size; i++) {
        int c = br.read();
        if (c == -1) {
            throw new IOException("Unexpected end of input");
        }
        sb.appendCodePoint((char) c);
    }
    record.setData(token, sb.toString());
}

private List<Adif2Record> records = new ArrayList<>();

public void read() throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(filePath));

    int intValue;
    boolean createToken = false;
    boolean createSize = false;
    boolean createType = false;
    StringBuilder token = new StringBuilder();
    StringBuilder size = new StringBuilder();
    Adif2Record record = new Adif2Record();

    while ((intValue = br.read()) != -1) {
        switch (intValue) {
            case '\n':
                break;
            case '<':
                createToken = true;
                break;
            case ':':
                if (createToken) {
                    // not in header
                    createToken = false;
                    createSize = true;
                } else if (createSize) {
                    createType = true;
                    createSize = false;
                }
                break;
            case '>':
                switch (token.toString().toLowerCase()) {
                    case "eor":
                    case "eoh":
                        records.add(record);
                        record = new Adif2Record();
                        break;
                    default:
                        createSize = false;
                        createType = false;
                        createData(br, token.toString(), str2int(size.toString()), record);
                }
                token.setLength(0);
                size.setLength(0);
                break;
            default:
                char cValue = (char) intValue;
                if (createToken) {
                    token.append(cValue);
                }
                if (createSize) {
                    size.append(cValue);
                }
                if (createType) {
                    // TODO
                }
        }

    }

}

private static int str2int(String s) {
    return s.isEmpty() ? 0 : Integer.parseInt(s);
}
public class Adif2Record {

    private final Map<String, String> data = new HashMap<>();

    public void setData(String key, String value) {
        data.put(key, value);
    }

    public Map<String, String> getData() {
        return data;
    }
}

关于Java解析ADIF文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42872287/

相关文章:

Java反射运行时性能

java - 我应该为 java.nio.Files 创建包装器以进行单元测试吗?

java - 如何在删除 Firebase 中的行后刷新 Recyclerview 适配器中的数据

java - 任何人都可以使用任何 Java 应用程序的代码吗?

c# - 如何从字符串返回枚举值?

PHP 将 mysql 的部分结果解析为 preg_replace 上的变量

java - 用于创建、解析和查询 XML 的最佳 Java 库

java - Matcher 是否显示正则表达式匹配的位置?