r - 解析纳斯达克 .tip 文件



>问题:我有一个来自纳斯达克的 .tip 文件,我需要解析。正式名称:GENIUM合并饲料
该文件是一个类似csv的文件,带有分号和换行符,用于不同结构的新条目,因此没有常量标题。但是它有一个相应的 xsd 模式文件,它应该描述内容和结构,但我看不到从文件到结构结果的明确方法。尝试过列表设置,其中 messageType 成为列表中的名称

x <- scan("cran_tasks/NOMX_Comm_Close2.tip", what="", sep="n")
y <- strsplit(x, ';')
names(y) <- sapply(y, `[[`, 1)
y <- sapply(y, `[`, -1, simplify = FALSE)
y <- sapply(y, as.list) 

该文件的结构如下:

messageType;key1Value;key2Value;...;..;/n  
messageType;key1Value;key2Value;.....;/n    
BDSr;i2;NAmGITS;  
BDx;i106;Si18;s2;SYmNC;NAmNASDAQ OMX Commodities;CNyNO;MIcNORX;  
BDm;i672;Si018171;s2;Ex106;NAmFuel Oil;SYmNCFO;TOTa+0200;LDa20141011;  
BDIs;i10142;SiNP;s2;ISsNP;NAmNord Pool ASA;  
m;i122745;t191500.001;Dt20170509;ISOcY;ISOtY;
m;i122745;t192808.721;Dt20170509;ISOcN;ISOtY;SEp275.45;  
Oi;i122745;t054425.600;OPi2840;

我已经设置了一个有效的sql代码来解析文件,但它已经证明是特定于案例的,即使是结构上的微小变化,例如不同键值对的顺序,也是健壮的。因此,我正在寻找利用信息结构的方法,以便能够制定强大且可维护的解决方案,最好是在 R 中。我已经尝试了一些正则表达式匹配,但我最终仍然有很多特定于上下文的代码,所以我希望使用包含 Key 信息的表或数据帧进行一些结构化可以制定可持续的解决方案。

任何提示或建议都非常受欢迎。

链接到 XML/XSD 文件和指定键的 HTML 工作表,以及一个 .tip 文件

提示消息格式 TIP 协议是一种标记文本协议。 一个 TIP 消息是用 分号。 标签是零个或多个大写字符,后跟 小写字符。 标记后紧跟值。 标签的示例包括"FLd"、"STa"。 消息中的第一个标记是 始终是消息类型。消息类型标记没有值。一个例子 的消息类型标记为"BDSh"。 IP 消息使用 UTF-8 编码 除非另有说明。 TIP 消息的最大长度为 用常量MAX_MESSAGE_LENGTH(2048 字节)表示。 任何 最大字段长度不包括任何转义字符"\"。 无空值 将被发送;消息类型标记和布尔标记 ( 标签本身的存在对应于"true"值)。 对于一个 十进制字段(即浮点数据类型)长度为 X,Y 其中 X 是字段整数部分的最大位数 (分隔符左侧)。Y 是小数位数(右边 分隔符)。 传播标签的顺序不是固定的,即 客户端不得对标签的顺序做出任何假设。唯一的 消息的固定组件是消息类型,它始终 放在消息数据中的第一个位置。 请注意,新消息和字段 可能会添加到协议的未来版本中。确保前进 兼容性,客户端应忽略无法识别的消息类型和 字段标记。

下面的data.table解决方案解析给定的 .tip 文件并返回带有标记和值对的 data.table。因此,这可能是进一步提取相关数据的良好起点。

library(data.table)
# read downloaded file from local disk
tip_wide <- fread(
"NOMX_Comm_Close2.tip"
, sep = "n"
, header = FALSE
)
# split tip messages into tag and value pairs
# thereby rehaping from wide to long format
# and adding a row number
tip_long <- tip_wide[, unlist(strsplit(V1, ";")), 
by = .(rn = seq_len(nrow(tip_wide)))]
# get message type tag as the first entry of each message
msg_type <- tip_long[, .(msg.type = first(V1)), by = rn]
# make message type a separate column for each tag-value-pair using join
# remove unnecessary rows
tip_result <- msg_type[long, on = "rn"][msg.type != V1]
# split tag and value pairs
tip_result[, c("tag", "value") := 
data.table(stringr::str_split_fixed(V1, "(?<=^[A-Z]{0,9}[a-z])", 2))]
tip_result
#           rn msg.type        V1 tag   value
#     1:     1     BDSr        i2   i       2
#     2:     1     BDSr   NAmGITS NAm    GITS
#     3:     2      BDx      i106   i     106
#     4:     2      BDx      Si18  Si      18
#     5:     2      BDx        s2   s       2
#    ---                                     
#905132: 95622     BDCl        s2   s       2
#905133: 95622     BDCl  i2368992   i 2368992
#905134: 95622     BDCl Il2368596  Il 2368596
#905135: 95622     BDCl       Op1  Op       1
#905136: 95622     BDCl       Ra1  Ra       1

请注意,value列的类型为 character。

正则表达式"(?<=^[A-Z]{0,9}[a-z])"使用后视断言(见?"stringi-search-regex")来定义拆分模式。请注意,此处使用{0,9}而不是*,因为后视模式不得是无界的(没有 * 或 + 运算符)。

最新更新