Blame | Last modification | View Log | RSS feed
package com.smartdukaan.cron.offercircular;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.regex.Pattern;/*** Resolves the "Credit cards" / "Debit Cards" cells to bank ids.** The alias map must be supplied by the caller (built from offers.bank +* offers.bank_alias) because the circular spells the same bank several ways across* pages: IDFC / IDFC BANK / IDFC FIRST BANK, Indusind / Indusland (a typo in the* source), AU / AU Bank / Au Small Finance Bank. Without aliasing, ingest creates* four IDFCs.** Note that UPI appears in these columns but is a payment mode, not an issuer, so it* is reported as a flag rather than resolved as a bank.*/public final class BankTextParser {/** Card-type and qualifier words that are not bank names. J and K are the halves* of "J&K" left behind by splitting on '&'; J&K is deliberately out of scope. */private static final Pattern NOISE = Pattern.compile("^(CC|DC|EMI|CARD|CARDS|BANK|ONLY|LFR|FINANCIAL|CREDIT|DEBIT|REG|FULL"+ "|SWIPE|AND|OR|THE|SELECTED|SELECTIVE|CARDLESS|CARDLESS EMI|CARDLES S"+ "|CARDLES|J|K|K BANK)$");private static final Pattern ALL_BANKS = Pattern.compile("ALL\\s*BANKS?");private static final Pattern ALL_BANKS_CLAUSE = Pattern.compile("ALL\\s*BANKS?\\s*(EXCEPT)?");private static final Pattern UPI = Pattern.compile("\\bUPI\\b");private static final Pattern PARENTHETICAL = Pattern.compile("\\(.*?\\)");private static final Pattern SEPARATOR = Pattern.compile("[,/&]| AND ");private static final Pattern WHITESPACE = Pattern.compile("\\s+");public static final class Result {private final List<Integer> bankIds = new ArrayList<>();private final List<String> unresolved = new ArrayList<>();private boolean allBanks;private boolean upi;public List<Integer> getBankIds() { return bankIds; }public List<String> getUnresolved() { return unresolved; }public boolean isAllBanks() { return allBanks; }public boolean isUpi() { return upi; }}private BankTextParser() { }public static Result parse(String cell, Map<String, Integer> aliasToBankId) {Result result = new Result();if (cell == null) {return result;}String text = cell.trim();if (text.isEmpty() || "-".equals(text) || "NA".equals(text) || "N/A".equals(text)) {return result;}String upper = text.toUpperCase();result.allBanks = ALL_BANKS.matcher(upper).find();result.upi = UPI.matcher(upper).find();// parentheticals are qualifiers ("(DC & CC)", "(LFR Only)"), not bank namesString body = PARENTHETICAL.matcher(upper).replaceAll(" ");body = ALL_BANKS_CLAUSE.matcher(body).replaceAll(" ");for (String token : SEPARATOR.split(body)) {String name = strip(WHITESPACE.matcher(token).replaceAll(" "), " .-");if (name.isEmpty() || NOISE.matcher(name).matches() || "UPI".equals(name)) {continue;}Integer bankId = aliasToBankId.get(name);if (bankId == null) {// progressively shorter prefixes: "HDFC DEBIT" -> "HDFC"for (int cut = name.length(); cut > 2; cut--) {bankId = aliasToBankId.get(name.substring(0, cut).trim());if (bankId != null) {break;}}}if (bankId != null) {if (!result.bankIds.contains(bankId)) {result.bankIds.add(bankId);}} else {result.unresolved.add(name);}}return result;}private static String strip(String s, String chars) {int from = 0;int to = s.length();while (from < to && chars.indexOf(s.charAt(from)) >= 0) { from++; }while (to > from && chars.indexOf(s.charAt(to - 1)) >= 0) { to--; }return s.substring(from, to);}}