package com.simuwang.daq.components; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import java.util.Calendar; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; public final class ReportParseUtils { /** * 行业配置的表格列名称 */ public static final List INDUSTRY_COLUMN_NAMES = ListUtil.list(false); /** * 份额变动的表格列名称 */ public static final List SHARE_CHANGE_COLUMN_NAMES = ListUtil.list(false); /** * 主要财务指标识别列名称 */ public static final List FINANCIAL_INDICATORS_COLUMN_NAMES = ListUtil.list(false); /** * 资产配置明细和大类关系映射 */ public static final Map ASSET_ALLOCATION_TYPE_MAPPER = MapUtil.newHashMap(32, true); static { // 财务指标 FINANCIAL_INDICATORS_COLUMN_NAMES.add("期末基金净资产"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("报告期期末单位净值"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("本期利润"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("本期已实现收益"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("期末可供分配利润"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("期末可供分配基金份额利润"); FINANCIAL_INDICATORS_COLUMN_NAMES.add("基金份额累计净值增长率"); // 中国证监会行业标准 INDUSTRY_COLUMN_NAMES.add("农、林、牧、渔业"); INDUSTRY_COLUMN_NAMES.add("采矿业"); INDUSTRY_COLUMN_NAMES.add("制造业"); INDUSTRY_COLUMN_NAMES.add("电力、热力、燃气及水生产和供应业"); INDUSTRY_COLUMN_NAMES.add("建筑业"); INDUSTRY_COLUMN_NAMES.add("批发和零售业"); INDUSTRY_COLUMN_NAMES.add("交通运输、仓储和邮政业"); INDUSTRY_COLUMN_NAMES.add("住宿和餐饮业"); INDUSTRY_COLUMN_NAMES.add("信息传输、软件和信息技术服务业"); INDUSTRY_COLUMN_NAMES.add("金融业"); INDUSTRY_COLUMN_NAMES.add("房地产业"); INDUSTRY_COLUMN_NAMES.add("租赁和商务服务业"); INDUSTRY_COLUMN_NAMES.add("科学研究和技术服务业"); INDUSTRY_COLUMN_NAMES.add("水利、环境和公共设施管理业"); INDUSTRY_COLUMN_NAMES.add("居民服务、修理和其他服务业"); INDUSTRY_COLUMN_NAMES.add("教育"); INDUSTRY_COLUMN_NAMES.add("卫生和社会工作"); INDUSTRY_COLUMN_NAMES.add("文化、体育和娱乐业"); INDUSTRY_COLUMN_NAMES.add("综合"); INDUSTRY_COLUMN_NAMES.add("港股通"); // 以下为国际标准 INDUSTRY_COLUMN_NAMES.add("能源"); INDUSTRY_COLUMN_NAMES.add("原材料"); INDUSTRY_COLUMN_NAMES.add("工业"); INDUSTRY_COLUMN_NAMES.add("非日常生活消费品"); INDUSTRY_COLUMN_NAMES.add("日常消费品"); INDUSTRY_COLUMN_NAMES.add("医疗保健"); INDUSTRY_COLUMN_NAMES.add("金融"); INDUSTRY_COLUMN_NAMES.add("信息技术"); INDUSTRY_COLUMN_NAMES.add("通讯服务"); INDUSTRY_COLUMN_NAMES.add("公用事业"); INDUSTRY_COLUMN_NAMES.add("房地产"); // 份额变动表格识别列 SHARE_CHANGE_COLUMN_NAMES.add("报告期期初基金份额总额"); SHARE_CHANGE_COLUMN_NAMES.add("减:报告期期间基金总赎回份额"); SHARE_CHANGE_COLUMN_NAMES.add("期末基金总份额/期末基金实缴总额"); SHARE_CHANGE_COLUMN_NAMES.add("报告期期间基金拆分变动份额"); SHARE_CHANGE_COLUMN_NAMES.add("报告期期间基金总申购份额"); // 资产配置 ASSET_ALLOCATION_TYPE_MAPPER.put("银行存款", "现金类资产"); // 境内未上市、未挂牌公司股权投资 ASSET_ALLOCATION_TYPE_MAPPER.put("股权投资", "境内未上市、未挂牌公司股权投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:优先股", "境内未上市、未挂牌公司股权投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("其他股权类投资", "境内未上市、未挂牌公司股权投资"); // 上市公司定向增发投资 ASSET_ALLOCATION_TYPE_MAPPER.put("上市公司定向增发投资", "上市公司定向增发投资"); // 新三板投资 ASSET_ALLOCATION_TYPE_MAPPER.put("新三板挂牌企业投资", "新三板投资"); // 境内证券投资规模 ASSET_ALLOCATION_TYPE_MAPPER.put("结算备付金", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("存出保证金", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("股票投资", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("债券投资", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:银行间市场债券", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:利率债", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:信用债", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("资产支持证券", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("基金投资(公募基金)", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:货币基金", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("期货及衍生品交易保证金", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("买入返售金融资产", "境内证券投资规模"); ASSET_ALLOCATION_TYPE_MAPPER.put("其他证券类标的", "境内证券投资规模"); // 资管计划投资 ASSET_ALLOCATION_TYPE_MAPPER.put("商业银行理财产品投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("信托计划投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("基金公司及其子公司资产管理计划投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("保险资产管理计划投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("证券公司及其子公司资产管理计划投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("期货公司及其子公司资产管理计划投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("私募基金产品投资", "资管计划投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("未在协会备案的合伙企业份额", "资管计划投资"); // 另类投资 ASSET_ALLOCATION_TYPE_MAPPER.put("另类投资", "另类投资"); // 境内债权类投资 ASSET_ALLOCATION_TYPE_MAPPER.put("银行委托贷款规模", "境内债权类投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("信托贷款", "境内债权类投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("应收账款投资", "境内债权类投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("各类受(收)益权投资", "境内债权类投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("票据(承兑汇票等)投资", "境内债权类投资"); ASSET_ALLOCATION_TYPE_MAPPER.put("其他债权投资", "境内债权类投资"); // 境外投资 ASSET_ALLOCATION_TYPE_MAPPER.put("境外投资", "境外投资"); // 其他资产 ASSET_ALLOCATION_TYPE_MAPPER.put("其他资产", "其他资产"); // 基金负债情况 ASSET_ALLOCATION_TYPE_MAPPER.put("债券回购总额", "基金负债情况"); ASSET_ALLOCATION_TYPE_MAPPER.put("融资、融券总额", "基金负债情况"); ASSET_ALLOCATION_TYPE_MAPPER.put("其中:融券总额", "基金负债情况"); ASSET_ALLOCATION_TYPE_MAPPER.put("银行借款总额", "基金负债情况"); ASSET_ALLOCATION_TYPE_MAPPER.put("其他融资总额", "基金负债情况"); } /** * 数据清洗,替换圆括号,包含中文或英文的圆括号 * * @param value / * @return / */ public static String cleaningValue(Object value) { return cleaningValue(value, true); } /** * 数据简单清洗,并全部转为字符串类型 * * @param value 待清洗的数据 * @param replaceParentheses 是否替换圆括号 * @return / */ public static String cleaningValue(Object value, boolean replaceParentheses) { String fieldValue = StrUtil.toStringOrNull(value); if (!StrUtil.isNullOrUndefined(fieldValue)) { // 特殊字符替换,空格替换为空字符 fieldValue = fieldValue .replace("\r", StrUtil.EMPTY) .replace(";", ";") .replaceAll(" ", StrUtil.EMPTY); if (replaceParentheses) { // 正则表达式匹配中文括号及其内容,并替换为空字符串 fieldValue = Pattern.compile("[(|(][^)]*[)|)]").matcher(fieldValue).replaceAll(StrUtil.EMPTY); } } // 如果仅有 “-” 该字段值为null if (Objects.equals("-", fieldValue)) { fieldValue = null; } return StrUtil.isBlank(fieldValue) ? null : fieldValue; } /** * 匹配分级基金名称(并且把母基金追加到第一行) * * @param text 文本内容 * @return / */ public static List matchTieredFund(String text) { List matches = ListUtil.list(false); if (StrUtil.isBlank(text)) { return matches; } // 使用正则表达式查找匹配项 Pattern pattern = Pattern.compile("[A-F]级|基金[A-F]"); Matcher matcher = pattern.matcher(text); // 收集所有匹配项 while (matcher.find()) { matches.add(matcher.group()); } // 提取字母并按字母顺序排序 List levels = matches.stream() .map(s -> s.replaceAll("[^A-F]", "")) .distinct() .sorted() .map(letter -> letter + "级") .collect(Collectors.toList()); levels.add(0, "母基金"); return levels; } /** * 匹配报告日期 * * @param string 文本内容 * @return 报告日期 */ public static String matchReportDate(String string) { if (string == null) { return null; } // 编译正则表达式模式 Pattern pat1 = Pattern.compile("(2\\d{3}).*([一二三四1234])季度"); // 2023年XXX3季度 Pattern pat2 = Pattern.compile("\\d{4}-\\d{2}-\\d{2}"); // 2023-12-31 Pattern pat3 = Pattern.compile("(2\\d{3})年年度"); // 2023年年度 Pattern pat4 = Pattern.compile("(\\d{4})年(\\d{1,2})月"); // 2023年12月 Pattern pat5 = Pattern.compile("\\d{4}\\d{2}\\d{2}"); // 20231231 Pattern pat6 = Pattern.compile("(2\\d{3})年度"); // 2023年度 // 创建Matcher对象 Matcher matcher1 = pat1.matcher(string); Matcher matcher2 = pat2.matcher(string); Matcher matcher3 = pat3.matcher(string); Matcher matcher4 = pat4.matcher(string); Matcher matcher5 = pat5.matcher(string); Matcher matcher6 = pat6.matcher(string); // 尝试匹配 if (matcher1.find()) { String year = matcher1.group(1); String quarter = matcher1.group(2); return switch (quarter) { case "一", "1" -> year + "-03-31"; case "二", "2" -> year + "-06-30"; case "三", "3" -> year + "-09-30"; case "四", "4" -> year + "-12-31"; default -> null; }; } else if (matcher2.find()) { return matcher2.group(); } else if (matcher5.find()) { return matcher5.group(); } else if (matcher3.find()) { return matcher3.group(1) + "-12-31"; } else if (matcher6.find()) { return matcher6.group(1) + "-12-31"; } else if (matcher4.find()) { String year = matcher4.group(1); String month = matcher4.group(2); int lastDayOfMonth = getLastDayOfMonth(Integer.parseInt(year), Integer.parseInt(month)); return year + "-" + padZero(month) + "-" + padZero(lastDayOfMonth + ""); } else { return null; } } /** * 匹配报告类型,如“季度”、“年度” * * @param string 输入字符串 * @return 匹配到的报告类型子字符串,如果没有匹配到则返回null */ public static String matchReportType(String string) { if (string == null) { return null; } // 所有报告的正则识别方式 String patterns = "年度|年报|季度|季报|季|月度|月报|月|年"; // 编译正则表达式模式 Pattern pattern = Pattern.compile(patterns); // 创建Matcher对象 Matcher matcher = pattern.matcher(string); // 尝试匹配 if (matcher.find()) { return matcher.group(); } else { return null; } } private static int getLastDayOfMonth(int year, int month) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month - 1); // Calendar.MONTH 是从0开始的 return calendar.getActualMaximum(Calendar.DAY_OF_MONTH); } private static String padZero(String number) { return String.format("%02d", Integer.parseInt(number)); } }