package com.github.sommeri.less4j.core.compiler.expressions.strings; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree; public abstract class AbstractStringReplacer <ARG> { public AbstractStringReplacer() { super(); } public String replaceIn(String originalValue, ARG replacementArgument, HiddenTokenAwareTree technicalUnderlying) { String replacedValue = replacementRound(originalValue, replacementArgument, technicalUnderlying); while (shouldIterate() && !equals(replacedValue, originalValue)) { originalValue = replacedValue; replacedValue = replacementRound(replacedValue, replacementArgument, technicalUnderlying); } return replacedValue; } protected abstract boolean shouldIterate(); private boolean equals(String replacedValue, String originalValue) { if (replacedValue==null) return originalValue==null; return replacedValue.equals(originalValue); } private String replacementRound(String originalValue, ARG replacementArgument, HiddenTokenAwareTree technicalUnderlying) { StringBuilder result = new StringBuilder(); List<MatchRange> matches = findMatches(originalValue); int lastEnd = 0; for (MatchRange matchRange : matches) { // add everything from the last end to match from result.append(originalValue.substring(lastEnd, matchRange.getFrom())); // replace match by value result.append(replacementValue(replacementArgument, technicalUnderlying, matchRange)); // update last end lastEnd = matchRange.getTo(); } // add everything from the last end to end of string if (lastEnd<originalValue.length()) result.append(originalValue.substring(lastEnd)); return result.toString(); } private List<MatchRange> findMatches(String originalValue) { List<MatchRange> result = new ArrayList<MatchRange>(); Matcher matcher = getPattern().matcher(originalValue); while (matcher.find()) { result.add(createMatchRange(matcher)); } return result; } private MatchRange createMatchRange(Matcher matcher) { String group = matcher.group(); return new MatchRange(matcher.start(), matcher.end(), extractMatchName(group), group); } protected abstract String extractMatchName(String group); protected abstract Pattern getPattern(); protected abstract String replacementValue(ARG replacementArgument, HiddenTokenAwareTree technicalUnderlying, MatchRange matchRange); }