StringUtil.java

  1. package org.drip.numerical.common;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  * Copyright (C) 2018 Lakshmi Krishnamurthy
  9.  * Copyright (C) 2017 Lakshmi Krishnamurthy
  10.  * Copyright (C) 2016 Lakshmi Krishnamurthy
  11.  * Copyright (C) 2015 Lakshmi Krishnamurthy
  12.  * Copyright (C) 2014 Lakshmi Krishnamurthy
  13.  * Copyright (C) 2013 Lakshmi Krishnamurthy
  14.  * Copyright (C) 2012 Lakshmi Krishnamurthy
  15.  *
  16.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  17.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  18.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  19.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  20.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  21.  *      and computational support.
  22.  *  
  23.  *      https://lakshmidrip.github.io/DROP/
  24.  *  
  25.  *  DROP is composed of three modules:
  26.  *  
  27.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  28.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  29.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  30.  *
  31.  *  DROP Product Core implements libraries for the following:
  32.  *  - Fixed Income Analytics
  33.  *  - Loan Analytics
  34.  *  - Transaction Cost Analytics
  35.  *
  36.  *  DROP Portfolio Core implements libraries for the following:
  37.  *  - Asset Allocation Analytics
  38.  *  - Asset Liability Management Analytics
  39.  *  - Capital Estimation Analytics
  40.  *  - Exposure Analytics
  41.  *  - Margin Analytics
  42.  *  - XVA Analytics
  43.  *
  44.  *  DROP Computational Core implements libraries for the following:
  45.  *  - Algorithm Support
  46.  *  - Computation Support
  47.  *  - Function Analysis
  48.  *  - Model Validation
  49.  *  - Numerical Analysis
  50.  *  - Numerical Optimizer
  51.  *  - Spline Builder
  52.  *  - Statistical Learning
  53.  *
  54.  *  Documentation for DROP is Spread Over:
  55.  *
  56.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  57.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  58.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  59.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  60.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  61.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  62.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  63.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  64.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  65.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  66.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  67.  *
  68.  *  Licensed under the Apache License, Version 2.0 (the "License");
  69.  *      you may not use this file except in compliance with the License.
  70.  *  
  71.  *  You may obtain a copy of the License at
  72.  *      http://www.apache.org/licenses/LICENSE-2.0
  73.  *  
  74.  *  Unless required by applicable law or agreed to in writing, software
  75.  *      distributed under the License is distributed on an "AS IS" BASIS,
  76.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  77.  *  
  78.  *  See the License for the specific language governing permissions and
  79.  *      limitations under the License.
  80.  */

  81. /**
  82.  * <i>StringUtil</i> implements string utility functions. It exports the following functions:
  83.  *  <ul>
  84.  *      <li>
  85.  *          Decompose + Transform string arrays into appropriate target type set/array/list, and vice versa
  86.  *      </li>
  87.  *      <li>
  88.  *          General-purpose String processor functions, such as GUID generator, splitter, type converter and
  89.  *              input checker
  90.  *      </li>
  91.  *  </ul>
  92.  *
  93.  * <br><br>
  94.  *  <ul>
  95.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  96.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  97.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical">Numerical Quadrature, Differentiation, Eigenization, Linear Algebra, and Utilities</a></li>
  98.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/numerical/common">Primitives/Array Manipulate Format Display Utilities</a></li>
  99.  *  </ul>
  100.  * <br><br>
  101.  *
  102.  * @author Lakshmi Krishnamurthy
  103.  */

  104. public class StringUtil {

  105.     /**
  106.      * Null serialized string
  107.      */

  108.     public static final java.lang.String NULL_SER_STRING = "<<null>>";

  109.     /**
  110.      * Serialization Version - ALWAYS prepend this on all derived classes
  111.      */

  112.     public static final double VERSION = 2.4;

  113.     /**
  114.      * Look for a match of the field in the input array
  115.      *
  116.      * @param strFieldToMatch Field To Match
  117.      * @param astrMatchSet Array of fields to compare with
  118.      * @param bCaseMatch TRUE - Match case
  119.      *
  120.      * @return TRUE - Match found according to the criteria specified
  121.      */

  122.     public static final boolean MatchInStringArray (
  123.         final java.lang.String strFieldToMatch,
  124.         final java.lang.String[] astrMatchSet,
  125.         final boolean bCaseMatch)
  126.     {
  127.         if (null == strFieldToMatch || strFieldToMatch.isEmpty() || null == astrMatchSet || 0 ==
  128.             astrMatchSet.length)
  129.             return false;

  130.         for (java.lang.String strMatchSetEntry : astrMatchSet) {
  131.             if (null == strMatchSetEntry || strMatchSetEntry.isEmpty()) continue;

  132.             if (strMatchSetEntry.equals (strFieldToMatch)) return true;

  133.             if (!bCaseMatch && strMatchSetEntry.equalsIgnoreCase (strFieldToMatch)) return true;
  134.         }

  135.         return false;
  136.     }

  137.     /**
  138.      * Look for a match of the field in the field set to an entry in the input array
  139.      *
  140.      * @param astrFieldToMatch Field Array To Match
  141.      * @param astrMatchSet Array of fields to compare with
  142.      * @param bCaseMatch TRUE - Match case
  143.      *
  144.      * @return TRUE - Match found according to the criteria specified
  145.      */

  146.     public static final boolean MatchInStringArray (
  147.         final java.lang.String[] astrFieldToMatch,
  148.         final java.lang.String[] astrMatchSet,
  149.         final boolean bCaseMatch)
  150.     {
  151.         if (null == astrFieldToMatch || 0 == astrFieldToMatch.length || null == astrMatchSet || 0 ==
  152.             astrMatchSet.length)
  153.             return false;

  154.         for (java.lang.String strFieldToMatch : astrFieldToMatch) {
  155.             if (MatchInStringArray (strFieldToMatch, astrMatchSet, bCaseMatch)) return true;
  156.         }

  157.         return false;
  158.     }

  159.     /**
  160.      * Format the given string parameter into an argument
  161.      *
  162.      * @param strArg String Argument
  163.      *
  164.      * @return Parameter from the Argument
  165.      */

  166.     public static final java.lang.String MakeStringArg (
  167.         final java.lang.String strArg)
  168.     {
  169.         if (null == strArg) return "null";

  170.         if (strArg.isEmpty()) return "\"\"";

  171.         return "\"" + strArg.trim() + "\"";
  172.     }

  173.     /**
  174.      * Check the Input String to Check for NULL - and return it
  175.      *
  176.      * @param strIn Input String
  177.      * @param bEmptyToNULL TRUE if Empty String needs to be converted to NULL
  178.      *
  179.      * @return The Processed String
  180.      */

  181.     public static final java.lang.String ProcessInputForNULL (
  182.         final java.lang.String strIn,
  183.         final boolean bEmptyToNULL)
  184.     {
  185.         if (null == strIn) return null;

  186.         if (strIn.isEmpty()) return bEmptyToNULL ? null : "";

  187.         if ("null".equalsIgnoreCase (strIn.trim())) return null;

  188.         if (strIn.trim().toUpperCase().startsWith ("NO")) return null;

  189.         return strIn;
  190.     }

  191.     /**
  192.      * Parse and Split the Input Phrase into a String Array using the specified Delimiter
  193.      *
  194.      * @param strPhrase Input Phrase
  195.      * @param strDelim Delimiter
  196.      *
  197.      * @return Array of Sub-Strings
  198.      */

  199.     public static final java.lang.String[] Split (
  200.         final java.lang.String strPhrase,
  201.         final java.lang.String strDelim)
  202.     {
  203.         if (null == strPhrase || strPhrase.isEmpty() || null == strDelim || strDelim.isEmpty()) return null;

  204.         java.util.List<java.lang.Integer> lsDelimIndex = new java.util.ArrayList<java.lang.Integer>();

  205.         int iDelimIndex = -1;

  206.         while (-1 != (iDelimIndex = strPhrase.indexOf (strDelim, iDelimIndex + 1)))
  207.             lsDelimIndex.add (iDelimIndex);

  208.         int iNumField = lsDelimIndex.size();

  209.         if (0 == iNumField) return null;

  210.         int iBeginIndex = 0;
  211.         java.lang.String[] astr = new java.lang.String[iNumField + 1];

  212.         for (int i = 0; i < iNumField; ++i) {
  213.             int iFinishIndex = lsDelimIndex.get (i);

  214.             astr[i] = iBeginIndex >= iFinishIndex ? "" : strPhrase.substring (iBeginIndex, iFinishIndex);

  215.             iBeginIndex = lsDelimIndex.get (i) + 1;
  216.         }

  217.         astr[iNumField] = strPhrase.substring (iBeginIndex);

  218.         return astr;
  219.     }

  220.     /**
  221.      * Check if the string represents an unitary boolean
  222.      *
  223.      * @param strUnitaryBoolean String input
  224.      *
  225.      * @return TRUE - Unitary Boolean
  226.      */

  227.     public static final boolean ParseFromUnitaryString (
  228.         final java.lang.String strUnitaryBoolean)
  229.     {
  230.         if (null == strUnitaryBoolean || strUnitaryBoolean.isEmpty() || !"1".equalsIgnoreCase
  231.             (strUnitaryBoolean.trim()))
  232.             return false;

  233.         return true;
  234.     }

  235.     /**
  236.      * Make an array of Integers from a string tokenizer
  237.      *
  238.      * @param st Tokenizer containing delimited doubles
  239.      *  
  240.      * @return Double array
  241.      */

  242.     public static final int[] MakeIntegerArrayFromStringTokenizer (
  243.         final java.util.StringTokenizer st)
  244.     {
  245.         if (null == st) return null;

  246.         java.util.List<java.lang.Integer> li = new java.util.ArrayList<java.lang.Integer>();

  247.         while (st.hasMoreTokens())
  248.             li.add (java.lang.Integer.parseInt (st.nextToken()));

  249.         if (0 == li.size()) return null;

  250.         int[] ai = new int[li.size()];

  251.         int i = 0;

  252.         for (int iValue : li)
  253.             ai[i++] = iValue;

  254.         return ai;
  255.     }

  256.     /**
  257.      * Make an array of double from a string tokenizer
  258.      *
  259.      * @param stdbl Tokenizer containing delimited doubles
  260.      *  
  261.      * @return Double array
  262.      */

  263.     public static final double[] MakeDoubleArrayFromStringTokenizer (
  264.         final java.util.StringTokenizer stdbl)
  265.     {
  266.         if (null == stdbl) return null;

  267.         java.util.List<java.lang.Double> lsdbl = new java.util.ArrayList<java.lang.Double>();

  268.         while (stdbl.hasMoreTokens())
  269.             lsdbl.add (java.lang.Double.parseDouble (stdbl.nextToken()));

  270.         if (0 == lsdbl.size()) return null;

  271.         double[] adbl = new double[lsdbl.size()];

  272.         int i = 0;

  273.         for (double dbl : lsdbl)
  274.             adbl[i++] = dbl;

  275.         return adbl;
  276.     }

  277.     /**
  278.      * Generate a GUID string
  279.      *
  280.      * @return String representing the GUID
  281.      */

  282.     public static final java.lang.String GUID()
  283.     {
  284.         return java.util.UUID.randomUUID().toString();
  285.     }

  286.     /**
  287.      * Split the string array into pairs of key-value doubles and returns them
  288.      *
  289.      * @param lsdblKey [out] List of Keys
  290.      * @param lsdblValue [out] List of Values
  291.      * @param strArray [in] String containing KV records
  292.      * @param strRecordDelim [in] Record Delimiter
  293.      * @param strKVDelim [in] Key-Value Delimiter
  294.      *
  295.      * @return True if parsing is successful
  296.      */

  297.     public static final boolean KeyValueListFromStringArray (
  298.         final java.util.List<java.lang.Double> lsdblKey,
  299.         final java.util.List<java.lang.Double> lsdblValue,
  300.         final java.lang.String strArray,
  301.         final java.lang.String strRecordDelim,
  302.         final java.lang.String strKVDelim)
  303.     {
  304.         if (null == strArray || strArray.isEmpty() || null == strRecordDelim || strRecordDelim.isEmpty() ||
  305.             null == strKVDelim || strKVDelim.isEmpty() || null == lsdblKey || null == lsdblValue)
  306.             return false;

  307.         java.lang.String[] astr = Split (strArray, strRecordDelim);

  308.         if (null == astr || 0 == astr.length) return false;

  309.         for (int i = 0; i < astr.length; ++i) {
  310.             if (null == astr[i] || astr[i].isEmpty()) return false;

  311.             java.lang.String[] astrRecord = Split (astr[i], strKVDelim);

  312.             if (null == astrRecord || 2 != astrRecord.length || null == astrRecord[0] ||
  313.                 astrRecord[0].isEmpty() || null == astrRecord[1] || astrRecord[1].isEmpty())
  314.                 return false;

  315.             lsdblKey.add (java.lang.Double.parseDouble (astrRecord[0]));

  316.             lsdblValue.add (java.lang.Double.parseDouble (astrRecord[1]));
  317.         }

  318.         return true;
  319.     }

  320.     /**
  321.      * Create a list of integers from a delimited string
  322.      *
  323.      * @param lsi [Output] List of Integers
  324.      * @param strList Delimited String input
  325.      * @param strDelim Delimiter
  326.      *
  327.      * @return True if successful
  328.      */

  329.     public static final boolean IntegerListFromString (
  330.         final java.util.List<java.lang.Integer> lsi,
  331.         final java.lang.String strList,
  332.         final java.lang.String strDelim)
  333.     {
  334.         if (null == lsi || null == strList || strList.isEmpty() || null == strDelim || strDelim.isEmpty())
  335.             return false;

  336.         java.lang.String[] astr = Split (strList, strDelim);

  337.         if (null == astr || 0 == astr.length) return false;

  338.         for (int i = 0; i < astr.length; ++i) {
  339.             if (null == astr[i] || astr[i].isEmpty()) continue;

  340.             lsi.add (java.lang.Integer.parseInt (astr[i]));
  341.         }

  342.         return true;
  343.     }

  344.     /**
  345.      * Create a list of booleans from a delimited string
  346.      *
  347.      * @param lsb [Output] List of Booleans
  348.      * @param strList Delimited String input
  349.      * @param strDelim Delimiter
  350.      *
  351.      * @return True if successful
  352.      */

  353.     public static final boolean BooleanListFromString (
  354.         final java.util.List<java.lang.Boolean> lsb,
  355.         final java.lang.String strList,
  356.         final java.lang.String strDelim)
  357.     {
  358.         if (null == lsb || null == strList || strList.isEmpty() || null == strDelim || strDelim.isEmpty())
  359.             return false;

  360.         java.lang.String[] astr = Split (strList, strDelim);

  361.         if (null == astr || 0 == astr.length) return false;

  362.         for (int i = 0; i < astr.length; ++i) {
  363.             if (null == astr[i] || astr[i].isEmpty()) continue;

  364.             lsb.add (java.lang.Boolean.parseBoolean (astr[i]));
  365.         }

  366.         return true;
  367.     }

  368.     /**
  369.      * Convert the String Array to a Record Delimited String
  370.      *
  371.      * @param astr Input String Array
  372.      * @param strRecordDelimiter The String Record Delimiter
  373.      * @param strNULL NULL String Indicator
  374.      *
  375.      * @return The Record Delimited String Array
  376.      */

  377.     public static final java.lang.String StringArrayToString (
  378.         final java.lang.String[] astr,
  379.         final java.lang.String strRecordDelimiter,
  380.         final java.lang.String strNULL)
  381.     {
  382.         if (null == astr || null == strRecordDelimiter || strRecordDelimiter.isEmpty() || null == strNULL ||
  383.             strNULL.isEmpty())
  384.             return null;

  385.         int iNumStr = astr.length;

  386.         if (0 == iNumStr) return null;

  387.         java.lang.StringBuffer sb = new java.lang.StringBuffer();

  388.         for (int i = 0; i < iNumStr; ++i) {
  389.             java.lang.String str = astr[i];

  390.             if (0 != i) sb.append (strRecordDelimiter);

  391.             sb.append (null == str || str.isEmpty() ? strNULL : str);
  392.         }

  393.         return sb.toString();
  394.     }

  395.     /**
  396.      * Indicate if the Input String is Empty
  397.      *
  398.      * @param str The Input String
  399.      *
  400.      * @return TRUE - The Input String is Empty
  401.      */

  402.     public static final boolean IsEmpty (
  403.         final java.lang.String str)
  404.     {
  405.         return null == str || str.isEmpty();
  406.     }

  407.     /**
  408.      * Indicate it the pair of Strings Match each other in Value
  409.      *
  410.      * @param strLeft The Left String
  411.      * @param strRight The Right String
  412.      *
  413.      * @return TRUE - The Strings Match
  414.      */

  415.     public static final boolean StringMatch (
  416.         final java.lang.String strLeft,
  417.         final java.lang.String strRight)
  418.     {
  419.         boolean bIsLeftEmpty = IsEmpty (strLeft);

  420.         boolean bIsRightEmpty = IsEmpty (strRight);

  421.         if (bIsLeftEmpty && bIsRightEmpty) return true;

  422.         if ((bIsLeftEmpty && !bIsRightEmpty) || (!bIsLeftEmpty && bIsRightEmpty)) return false;

  423.         return strLeft.equalsIgnoreCase (strRight);
  424.     }
  425. }