1 /* 2 * aTunes 3 * Copyright (C) Alex Aranda, Sylvain Gaudard and contributors 4 * 5 * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors 6 * 7 * http://www.atunes.org 8 * http://sourceforge.net/projects/atunes 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 package net.sourceforge.atunes.kernel.modules.pattern; 22 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 import java.util.List; 26 import java.util.Map; 27 28 import net.sourceforge.atunes.utils.StringUtils; 29 30 /** 31 * Extracts patterns from strings 32 * @author alex 33 * 34 */ 35 public final class PatternMatcher { 36 37 private Patterns patterns; 38 39 /** 40 * @param patterns 41 */ setPatterns(Patterns patterns)42 public void setPatterns(Patterns patterns) { 43 this.patterns = patterns; 44 } 45 46 /** 47 * Returns a map containing string values result of matching a pattern 48 * against a string 49 * 50 * @param pattern 51 * @param value 52 * @param onlyMassiveRecognitionPatterns 53 * @return 54 */ getPatternMatches(String pattern, String value, boolean onlyMassiveRecognitionPatterns)55 public Map<String, String> getPatternMatches(String pattern, String value, boolean onlyMassiveRecognitionPatterns) { 56 Map<String, String> matches = new HashMap<String, String>(); 57 58 if (pattern == null || value == null) { 59 return matches; 60 } 61 62 String patternsString = pattern.trim(); 63 64 // Get all non-pattern sequences not blank 65 List<String> nonPatternSequences = getNonPatternSequences(patternsString); 66 67 int valueIndex = 0; 68 int patternsStringIndex = 0; 69 70 int i = 0; 71 String matchedPattern = null; 72 String matchedValue = null; 73 74 // Start parsing patterns string 75 while (patternsStringIndex < patternsString.length() && valueIndex < value.length()) { 76 String nonPatternSequence = getNextNonPatternSequence(nonPatternSequences, i); 77 78 matchedPattern = getMatchedPattern(patternsString, nonPatternSequence, patternsStringIndex); 79 matchedValue = getMatchedValue(value, nonPatternSequence, valueIndex); 80 81 patternsStringIndex = updateIndex(nonPatternSequence, patternsStringIndex, matchedPattern); 82 valueIndex = updateIndex(nonPatternSequence, valueIndex, matchedValue); 83 84 if (!checkAndAddMatch(matchedPattern, matchedValue, matches)) { 85 return new HashMap<String, String>(); 86 } 87 88 i++; 89 } 90 91 // Now return only necessary patterns 92 return processPatternsFound(onlyMassiveRecognitionPatterns, matches); 93 } 94 95 /** 96 * @param patternsString 97 * @return 98 */ getNonPatternSequences(String patternsString)99 private List<String> getNonPatternSequences(String patternsString) { 100 String[] nonPatternSequencesArray = patternsString.split(StringUtils.getString(AbstractPattern.PATTERN_NAME_FIRST_CHAR, '.')); 101 List<String> nonPatternSequences = new ArrayList<String>(); 102 for (String nonPatternSequence : nonPatternSequencesArray) { 103 if (!nonPatternSequence.isEmpty()) { 104 nonPatternSequences.add(nonPatternSequence); 105 } 106 } 107 return nonPatternSequences; 108 } 109 110 /** 111 * @param nonPatternSequences 112 * @param i 113 * @return 114 */ getNextNonPatternSequence(List<String> nonPatternSequences, int i)115 private String getNextNonPatternSequence(List<String> nonPatternSequences, int i) { 116 String nonPatternSequence = null; 117 if (i < nonPatternSequences.size()) { 118 nonPatternSequence = nonPatternSequences.get(i); 119 } 120 return nonPatternSequence; 121 } 122 123 /** 124 * @param nonPatternSequence 125 * @param stringIndex 126 * @param matched 127 * @return 128 */ updateIndex(String nonPatternSequence, int stringIndex, String matched)129 private int updateIndex(String nonPatternSequence, int stringIndex, String matched) { 130 return stringIndex + matched.length() + (nonPatternSequence != null ? nonPatternSequence.length() : 0); 131 } 132 checkAndAddMatch(String matchedPattern, String matchedValue, Map<String, String> matches)133 private boolean checkAndAddMatch(String matchedPattern, String matchedValue, Map<String, String> matches) { 134 // Force upper case patterns 135 String match = matchedPattern.toUpperCase(); 136 137 // Duplicate patterns are not allowed (despite being ? pattern) so we return an empty map 138 if (isDuplicatedPattern(matches, match)) { 139 return false; 140 } 141 142 addMatch(matches, match, matchedValue); 143 return true; 144 } 145 146 /** 147 * @param onlyMassiveRecognitionPatterns 148 * @param matches 149 * @return 150 */ processPatternsFound(boolean onlyMassiveRecognitionPatterns, Map<String, String> matches)151 private Map<String, String> processPatternsFound(boolean onlyMassiveRecognitionPatterns, Map<String, String> matches) { 152 Map<String, String> result = new HashMap<String, String>(); 153 List<AbstractPattern> patternsToBeUsed = onlyMassiveRecognitionPatterns ? patterns.getMassiveRecognitionPatterns() : patterns.getPatternsList(); 154 for (AbstractPattern p : patternsToBeUsed) { 155 if (matches.containsKey(p.getPattern())) { 156 result.put(p.getName(), matches.get(p.getPattern())); 157 } 158 } 159 return result; 160 } 161 162 /** 163 * @param matches 164 * @param matchedPattern 165 * @param matchedValue 166 */ addMatch(Map<String, String> matches, String matchedPattern, String matchedValue)167 private void addMatch(Map<String, String> matches, String matchedPattern, String matchedValue) { 168 // Ignore ? pattern 169 if (!matchedPattern.equals(patterns.getAnyPattern().getPattern())) { 170 matches.put(matchedPattern, matchedValue.trim()); 171 } 172 } 173 174 /** 175 * @param matches 176 * @param matchedPattern 177 * @return 178 */ isDuplicatedPattern(Map<String, String> matches, String matchedPattern)179 private boolean isDuplicatedPattern(Map<String, String> matches, 180 String matchedPattern) { 181 return !matchedPattern.equals(patterns.getAnyPattern().getPattern()) && matches.containsKey(matchedPattern); 182 } 183 getMatchedPattern(String patternsString, String nonPatternSequence, int patternsStringIndex)184 private String getMatchedPattern(String patternsString, String nonPatternSequence, int patternsStringIndex) { 185 if (nonPatternSequence != null) { 186 // Get index of current non pattern sequence 187 int indexAtPatternsString = patternsString.indexOf(nonPatternSequence, patternsStringIndex); 188 // We found a matched pattern 189 return patternsString.substring(patternsStringIndex, indexAtPatternsString); 190 } else { 191 return patternsString.substring(patternsStringIndex); 192 } 193 } 194 getMatchedValue(String value, String nonPatternSequence, int valueIndex)195 private String getMatchedValue(String value, String nonPatternSequence, int valueIndex) { 196 if (nonPatternSequence != null) { 197 int indexAtValueString = value.indexOf(nonPatternSequence, valueIndex); 198 // If value string ended without finding non pattern sequence, then the next pattern is substring 199 // from valueIndex to end of string 200 // NOTE this is a less restricted pattern search, as means that the last patterns in a pattern string 201 // are optional 202 if (indexAtValueString == -1) { 203 indexAtValueString = value.length(); 204 } 205 return value.substring(valueIndex, indexAtValueString); 206 } else { 207 return value.substring(valueIndex); 208 } 209 } 210 } 211