123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- 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<String> INDUSTRY_COLUMN_NAMES = ListUtil.list(false);
- /**
- * 份额变动的表格列名称
- */
- public static final List<String> SHARE_CHANGE_COLUMN_NAMES = ListUtil.list(false);
- /**
- * 主要财务指标识别列名称
- */
- public static final List<String> FINANCIAL_INDICATORS_COLUMN_NAMES = ListUtil.list(false);
- /**
- * 资产配置明细和大类关系映射
- */
- public static final Map<String, String> 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<String> matchTieredFund(String text) {
- List<String> 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<String> 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));
- }
- }
|