package io.monokkel.core.utils; import com.google.common.base.CharMatcher; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.stream.Collectors; import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Lists.newArrayList; /** * Created by tarjei on 20/09/14. */ public class CleanerFunction implements MapTransformationFunction<String,Object>{ public static final String VIM_SEARCH_AND_REPLACE_PATTERN = "(?=.*/.*/g)s/.*"; private Logger log = LoggerFactory.getLogger(CleanerFunction.class); public static final char REPLACEMENT_WHITESPACE = ' '; @Override public Object transform(final String key, final Object value, final Map<String, Object> transformationMap) { final Set<Map.Entry<String, Object>> expressionEntries = transformationMap.entrySet(); return value instanceof String ? cleanStringWithKey(key,value,expressionEntries): value; } private Object cleanStringWithKey(final String key, final Object value, final Set<Map.Entry<String, Object>> expressionEntries) { String castedValue = value.toString(); // Regular expressions do not match on char whitespaces ascii < 39 // This is therefore a hack! final String whiteSpaceRemovedString = CharMatcher.WHITESPACE.collapseFrom(castedValue, REPLACEMENT_WHITESPACE); final String extractedExpression = findAllSingleExpressionsThatMatchesKey(key, expressionEntries); // Filter will remove all none String elements // Arrays with subobjects will not work final List<String> expressions = newArrayList(filter(findAllMultiExpressionThatMatchesKey(key, expressionEntries), String.class)); if(!StringUtils.isEmpty(extractedExpression)) { return replaceByExpressionOrVimReplace(whiteSpaceRemovedString, extractedExpression); } if(expressions.size() > 1){ return expressions.stream().reduce(whiteSpaceRemovedString, this::replaceByExpressionOrVimReplace); } else { return whiteSpaceRemovedString; } } private String replaceByExpressionOrVimReplace(String s, String extractedExpression) { log.debug("Clean {} with expression {}",s,extractedExpression); if(extractedExpression.matches(VIM_SEARCH_AND_REPLACE_PATTERN)){ final List<String> expressionSplit = Arrays.asList(extractedExpression.split("/", 5)); List<String> expressionList = splitVimSearchIntoIndividualExpressions(expressionSplit); if(expressionList.size() == 2){ return s.replaceAll(expressionList.get(0),expressionList.get(1)); } else { log.warn("Failed to parse expression {}. Please make sure that it is in the format s/text/rext/g",extractedExpression); return s; } } else { return s.replaceAll(extractedExpression, ""); } } private List<String> splitVimSearchIntoIndividualExpressions(List<String> expressionSplit) { return expressionSplit.stream().filter(split -> !StringUtils.isEmpty(split)).filter(split -> !split.equals("s")).filter(split -> !split.equals("g")).collect(Collectors.toList()); } private String findAllSingleExpressionsThatMatchesKey(String key, Set<Map.Entry<String, Object>> expressionEntries) { return expressionEntries.stream() .filter(expression -> (expression.getKey().equals(key) && expression.getValue() instanceof String)) .map(expression -> (String) expression.getValue()).reduce("", (a, b) -> a + b); } private ArrayList findAllMultiExpressionThatMatchesKey(String key, Set<Map.Entry<String, Object>> expressionEntries) { return expressionEntries.stream(). filter(ex -> (ex.getKey().equals(key) && ex.getValue() instanceof ArrayList)) .map(ex -> (ArrayList) ex.getValue()) .reduce(newArrayList(), (ex1, ex2) -> newArrayList(concat(ex1, ex2))); } }