![JAR search and dependency download from the Maven repository](/logo.png)
net.yadaframework.raw.YadaRegexUtil Maven / Gradle / Ivy
package net.yadaframework.raw;
import java.util.Hashtable;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Miscellaneous Regular Expression functions
*
*/
public class YadaRegexUtil {
private final transient Logger log = LoggerFactory.getLogger(getClass());
private Map patternCache = new Hashtable(); // Not a HashMap
/**
* Escapes dots in regular expressions, replacing them with \.
* @param source
* @return
*/
public String escapeDots(String source) {
return source.replace(".", "\\.");
}
/**
* Return a compiled Pattern, either from the cache or new.
* @param pattern
* @return a Pattern or null id the pattern parameter is null
*/
public Pattern getOrCreatePattern(String pattern) {
return getOrCreatePattern(pattern, null);
}
/**
* Return a compiled Pattern, either from the cache or new, with case-insensitive and dotall flags set.
* @param pattern
* @param patternCache a Hashtable to store compiled patterns. Can be null to use the default.
* @return a Pattern or null id the pattern parameter is null
*/
public Pattern getOrCreatePattern(String pattern, Map patternCache) {
if (pattern==null) {
return null;
}
if (patternCache==null) {
patternCache = this.patternCache;
}
Pattern compiledPattern = patternCache.get(pattern);
if (compiledPattern==null) { // Don't care about synchronizing as redundant puts won't harm (they'll eventually cease)
compiledPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
patternCache.put(pattern, compiledPattern);
if (log.isDebugEnabled()) {
log.debug("Pattern not found in cache: '{}' (added) - total size = {}", pattern, patternCache.size());
}
}
return compiledPattern;
}
/**
* Return a matcher for the given source document and pattern. Compiled Pattern objects are cached.
* @param source the document that has to be matched against the pattern
* @param pattern the pattern to find in the document, or null for null result
* @return a new Matcher ready for use, or null if pattern is null
*/
public Matcher createMatcher(String source, String pattern) {
return createMatcher(source, pattern, null);
}
/**
* Return a matcher for the given source document and pattern. Compiled Pattern objects are cached.
* @param source the document that has to be matched against the pattern
* @param pattern the pattern to find in the document, or null for null result
* @param patternCache the Hastable that holds compiled patterns, can be null to use the default cache
* @return a new Matcher ready for use, or null if pattern is null
*/
public Matcher createMatcher(String source, String pattern, Map patternCache) {
if (patternCache==null) {
patternCache = this.patternCache;
}
Pattern compiledPattern = getOrCreatePattern(pattern, patternCache);
return compiledPattern==null?null:compiledPattern.matcher(source);
}
/**
* Performs a find-and-replace in a delimited area of the source, returning the source with replacements applied.
* @param source the text to be searched
* @param startPattern pattern that identifies the region start
* @param endPattern pattern that identifies the region end
* @param repeatRegion true if the region has to be searched many times in the source
* @param replacer the object performing the replacement within the region
* @return the source where the replacer has been applied within the delimited region
*/
public String replaceInRegion(String source, String startPattern, String endPattern, boolean repeatRegion, YadaRegexReplacer replacer) {
StringBuffer result = new StringBuffer();
Matcher regionMatcher = this.createMatcher(source, "(" + startPattern + ")" + "(.*?)" + "(" + endPattern + ")");
while (regionMatcher.find()) {
try {
regionMatcher.appendReplacement(result, ""); // Append all characters before the end of the region startPattern
result.append(regionMatcher.group(1)); // Append the start pattern
String toBeReplaced = regionMatcher.group(2);
if (toBeReplaced.length()>0) {
result.append(replacer.apply(toBeReplaced)); // Can't put this in appendReplacement because it interprets $ and \
}
result.append(regionMatcher.group(3)); // Append the end pattern
if (!repeatRegion) {
break;
}
} catch (Exception e) {
log.error("Failed to replace in region (ignored)", e);
}
}
regionMatcher.appendTail(result);
return result.toString();
}
/**
* Searches a region of text for a pattern that contains a capturing group, and returns the captured group.
* @param source the text to search
* @param startPattern a regular expression that identifies the start of the region, null to search from start.
* The matched text is excluded from search.
* @param endPattern a regular expression that identifies the end of the region, null to search to the end.
* The matched text is excluded from search.
* @param extractPattern a regular expression with a capturing group, null to return the whole region
* @return the text matched by the first capturing group of extractorPattern, or the empty string
*/
public String extractInRegion(String source, String startPattern, String endPattern, String extractPattern) {
startPattern=(startPattern==null)?"\\A":startPattern; // null is beginning of document
endPattern=(endPattern==null)?"\\z":endPattern; // null is end of document
Matcher regionMatcher = this.createMatcher(source, startPattern + "(.*?)" + endPattern);
try {
if (regionMatcher.find()) {
String region = regionMatcher.group(1); // "(.*?)"
if (extractPattern==null) {
return region;
}
Matcher extractor = this.createMatcher(region, extractPattern);
if (extractor.find()) {
return extractor.group(1);
}
}
} catch (Exception e) {
log.error("Failed to search in region (ignored)", e);
}
return "";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy