<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.text;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.Validate;
import org.apache.commons.text.lookup.StringLookup;
import org.apache.commons.text.lookup.StringLookupFactory;
import org.apache.commons.text.matcher.StringMatcher;
import org.apache.commons.text.matcher.StringMatcherFactory;

/**
 * Substitutes variables within a string by values.
 * <p>
 * This class takes a piece of text and substitutes all the variables within it. The default definition of a variable is
 * {@code ${variableName}}. The prefix and suffix can be changed via constructors and set methods.
 * </p>
 * <p>
 * Variable values are typically resolved from a map, but could also be resolved from system properties, or by supplying
 * a custom variable resolver.
 * </p>
 * <h2>Using System Properties</h2>
 * <p>
 * The simplest example is to use this class to replace Java System properties. For example:
 * </p>
 *
 * <pre>
 * StringSubstitutor
 *     .replaceSystemProperties("You are running with java.version = ${java.version} and os.name = ${os.name}.");
 * </pre>
 *
 * <h2>Using a Custom Map</h2>
 * <p>
 * Typical usage of this class follows the following pattern:
 * </p>
 * <ul>
 * <li>Create and initialize a StringSubstitutor with the map that contains the values for the variables you want to
 * make available.</li>
 * <li>Optionally set attributes like variable prefix, variable suffix, default value delimiter, and so on.</li>
 * <li>Call the {@code replace()} method with in the source text for interpolation.</li>
 * <li>The returned text contains all variable references (as long as their values are known) as resolved.</li>
 * </ul>
 * <p>
 * For example:
 * </p>
 *
 * <pre>
 * // Build map
 * Map&lt;String, String&gt; valuesMap = new HashMap&lt;&gt;();
 * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
 * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
 * String templateString = &quot;The ${animal} jumped over the ${target}.&quot;;
 *
 * // Build StringSubstitutor
 * StringSubstitutor sub = new StringSubstitutor(valuesMap);
 *
 * // Replace
 * String resolvedString = sub.replace(templateString);
 * </pre>
 *
 * <p>
 * yielding:
 * </p>
 *
 * <pre>
 * "The quick brown fox jumped over the lazy dog."
 * </pre>
 *
 * <h2>Providing Default Values</h2>
 * <p>
 * You can set a default value for unresolved variables. The default value for a variable can be appended to the
 * variable name after the variable default value delimiter. The default value of the variable default value delimiter
 * is ":-", as in bash and other *nix shells.
 * </p>
 * <p>
 * You can set the variable value delimiter with {@link #setValueDelimiterMatcher(StringMatcher)},
 * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}.
 * </p>
 * <p>
 * For example:
 * </p>
 * 
 * <pre>
 * // Build map
 * Map&lt;String, String&gt; valuesMap = new HashMap&lt;&gt;();
 * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
 * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
 * String templateString = &quot;The ${animal} jumped over the ${target}. ${undefined.number:-1234567890}.&quot;;
 *
 * // Build StringSubstitutor
 * StringSubstitutor sub = new StringSubstitutor(valuesMap);
 *
 * // Replace
 * String resolvedString = sub.replace(templateString);
 * </pre>
 *
 * <p>
 * yielding:
 * </p>
 *
 * <pre>
 * "The quick brown fox jumped over the lazy dog. 1234567890."
 * </pre>
 *
 * <p>
 * {@code StringSubstitutor} supports throwing exceptions for unresolved variables, you enable this by setting calling
 * {@link #setEnableUndefinedVariableException(boolean)} with {@code true}.
 * </p>
 *
 * <h2>Reusing Instances</h2>
 * <p>
 * Static shortcut methods cover the most common use cases. If multiple replace operations are to be performed, creating
 * and reusing an instance of this class will be more efficient.
 * </p>
 *
 * <h2>Using Interpolation</h2>
 * <p>
 * The default interpolator let's you use string lookups like:
 * </p>
 *
 * <pre>
 * final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
 * interpolator.setEnableSubstitutionInVariables(true); // Allows for nested $'s.
 * final String text = interpolator.replace(
 *       "Base64 Decoder:        ${base64Decoder:SGVsbG9Xb3JsZCE=}\n"
 *     + "Base64 Encoder:        ${base64Encoder:HelloWorld!}\n"
 *     + "Java Constant:         ${const:java.awt.event.KeyEvent.VK_ESCAPE}\n"
 *     + "Date:                  ${date:yyyy-MM-dd}\n" 
 *     + "DNS:                   ${dns:address|apache.org}\n"
 *     + "Environment Variable:  ${env:USERNAME}\n"
 *     + "File Content:          ${file:UTF-8:src/test/resources/document.properties}\n"
 *     + "Java:                  ${java:version}\n" 
 *     + "Localhost:             ${localhost:canonical-name}\n"
 *     + "Properties File:       ${properties:src/test/resources/document.properties::mykey}\n"
 *     + "Resource Bundle:       ${resourceBundle:org.example.testResourceBundleLookup:mykey}\n"
 *     + "Script:                ${script:javascript:3 + 4}\n" 
 *     + "System Property:       ${sys:user.dir}\n"
 *     + "URL Decoder:           ${urlDecoder:Hello%20World%21}\n"
 *     + "URL Encoder:           ${urlEncoder:Hello World!}\n"
 *     + "URL Content (HTTP):    ${url:UTF-8:http://www.apache.org}\n"
 *     + "URL Content (HTTPS):   ${url:UTF-8:https://www.apache.org}\n"
 *     + "URL Content (File):    ${url:UTF-8:file:///${sys:user.dir}/src/test/resources/document.properties}\n"
 *     + "XML XPath:             ${xml:src/test/resources/document.xml:/root/path/to/node}\n");
 * </pre>
 * <p>
 * For documentation of each lookup, see {@link StringLookupFactory}.
 * </p>
 *
 * <h2>Using Recursive Variable Replacement</h2>
 * <p>
 * Variable replacement can work recursively by calling {@link #setEnableSubstitutionInVariables(boolean)} 
 * with {@code true}. If a variable value contains a variable then that variable will
 * also be replaced. Cyclic replacements are detected and will throw an exception.<commit_msg>Checkstyle.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.text;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.Validate;
import org.apache.commons.text.lookup.StringLookup;
import org.apache.commons.text.lookup.StringLookupFactory;
import org.apache.commons.text.matcher.StringMatcher;
import org.apache.commons.text.matcher.StringMatcherFactory;

/**
 * Substitutes variables within a string by values.
 * <p>
 * This class takes a piece of text and substitutes all the variables within it. The default definition of a variable is
 * {@code ${variableName}}. The prefix and suffix can be changed via constructors and set methods.
 * </p>
 * <p>
 * Variable values are typically resolved from a map, but could also be resolved from system properties, or by supplying
 * a custom variable resolver.
 * </p>
 * <h2>Using System Properties</h2>
 * <p>
 * The simplest example is to use this class to replace Java System properties. For example:
 * </p>
 *
 * <pre>
 * StringSubstitutor
 *     .replaceSystemProperties("You are running with java.version = ${java.version} and os.name = ${os.name}.");
 * </pre>
 *
 * <h2>Using a Custom Map</h2>
 * <p>
 * Typical usage of this class follows the following pattern:
 * </p>
 * <ul>
 * <li>Create and initialize a StringSubstitutor with the map that contains the values for the variables you want to
 * make available.</li>
 * <li>Optionally set attributes like variable prefix, variable suffix, default value delimiter, and so on.</li>
 * <li>Call the {@code replace()} method with in the source text for interpolation.</li>
 * <li>The returned text contains all variable references (as long as their values are known) as resolved.</li>
 * </ul>
 * <p>
 * For example:
 * </p>
 *
 * <pre>
 * // Build map
 * Map&lt;String, String&gt; valuesMap = new HashMap&lt;&gt;();
 * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
 * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
 * String templateString = &quot;The ${animal} jumped over the ${target}.&quot;;
 *
 * // Build StringSubstitutor
 * StringSubstitutor sub = new StringSubstitutor(valuesMap);
 *
 * // Replace
 * String resolvedString = sub.replace(templateString);
 * </pre>
 *
 * <p>
 * yielding:
 * </p>
 *
 * <pre>
 * "The quick brown fox jumped over the lazy dog."
 * </pre>
 *
 * <h2>Providing Default Values</h2>
 * <p>
 * You can set a default value for unresolved variables. The default value for a variable can be appended to the
 * variable name after the variable default value delimiter. The default value of the variable default value delimiter
 * is ":-", as in bash and other *nix shells.
 * </p>
 * <p>
 * You can set the variable value delimiter with {@link #setValueDelimiterMatcher(StringMatcher)},
 * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}.
 * </p>
 * <p>
 * For example:
 * </p>
 *
 * <pre>
 * // Build map
 * Map&lt;String, String&gt; valuesMap = new HashMap&lt;&gt;();
 * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
 * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
 * String templateString = &quot;The ${animal} jumped over the ${target}. ${undefined.number:-1234567890}.&quot;;
 *
 * // Build StringSubstitutor
 * StringSubstitutor sub = new StringSubstitutor(valuesMap);
 *
 * // Replace
 * String resolvedString = sub.replace(templateString);
 * </pre>
 *
 * <p>
 * yielding:
 * </p>
 *
 * <pre>
 * "The quick brown fox jumped over the lazy dog. 1234567890."
 * </pre>
 *
 * <p>
 * {@code StringSubstitutor} supports throwing exceptions for unresolved variables, you enable this by setting calling
 * {@link #setEnableUndefinedVariableException(boolean)} with {@code true}.
 * </p>
 *
 * <h2>Reusing Instances</h2>
 * <p>
 * Static shortcut methods cover the most common use cases. If multiple replace operations are to be performed, creating
 * and reusing an instance of this class will be more efficient.
 * </p>
 *
 * <h2>Using Interpolation</h2>
 * <p>
 * The default interpolator let's you use string lookups like:
 * </p>
 *
 * <pre>
 * final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
 * interpolator.setEnableSubstitutionInVariables(true); // Allows for nested $'s.
 * final String text = interpolator.replace(
 *       "Base64 Decoder:        ${base64Decoder:SGVsbG9Xb3JsZCE=}\n"
 *     + "Base64 Encoder:        ${base64Encoder:HelloWorld!}\n"
 *     + "Java Constant:         ${const:java.awt.event.KeyEvent.VK_ESCAPE}\n"
 *     + "Date:                  ${date:yyyy-MM-dd}\n"
 *     + "DNS:                   ${dns:address|apache.org}\n"
 *     + "Environment Variable:  ${env:USERNAME}\n"
 *     + "File Content:          ${file:UTF-8:src/test/resources/document.properties}\n"
 *     + "Java:                  ${java:version}\n"
 *     + "Localhost:             ${localhost:canonical-name}\n"
 *     + "Properties File:       ${properties:src/test/resources/document.properties::mykey}\n"
 *     + "Resource Bundle:       ${resourceBundle:org.example.testResourceBundleLookup:mykey}\n"
 *     + "Script:                ${script:javascript:3 + 4}\n"
 *     + "System Property:       ${sys:user.dir}\n"
 *     + "URL Decoder:           ${urlDecoder:Hello%20World%21}\n"
 *     + "URL Encoder:           ${urlEncoder:Hello World!}\n"
 *     + "URL Content (HTTP):    ${url:UTF-8:http://www.apache.org}\n"
 *     + "URL Content (HTTPS):   ${url:UTF-8:https://www.apache.org}\n"
 *     + "URL Content (File):    ${url:UTF-8:file:///${sys:user.dir}/src/test/resources/document.properties}\n"
 *     + "XML XPath:             ${xml:src/test/resources/document.xml:/root/path/to/node}\n");
 * </pre>
 * <p>
 * For documentation of each lookup, see {@link StringLookupFactory}.
 * </p>
 *
 * <h2>Using Recursive Variable Replacement</h2>
 * <p>
 * Variable replacement can work recursively by calling {@link #setEnableSubstitutionInVariables(boolean)}
 * with {@code true}. If a variable value contains a variable then that variable will
 * also be replaced. Cyclic replacements are detected and will throw an exception.
{'fraction_non_alphanumeric': 0.13310044913381336, 'fraction_numerical': 0.0081271832893705, 'mean_word_length': 3.6496519721577725, 'pattern_counts': {'":': 2, '<': 129, '<?xml version=': 0, '>': 129, 'https://': 2, 'lorem ipsum': 0, 'www.': 6, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5146953', 'n_tokens_mistral': 4278, 'n_tokens_neox': 4124, 'n_words': 1357}