This is a update of this question since the requirements for this task changed.
I have a function that takes a description as a String
and returns a shortened version of the description.
The shortening is done by checking if a word matches the key of the Map<String,String> MAPPER
and replaces the word by its abbreviation defined as the value in the Map
. If the word cannot be found in the Map
it will not be replaced (it stays the same).
If the value of a word is <remove>
the word will be removed from the output string
If the value of a word/character is <remove after>
everything after that word/character will be removed from the output string.
If the value of a word/character is <remove after incl>
everything after that word/character will be removed from the output string. Including the word/character itself
If the value of a word is <remove before>
everything up to that word will removed from the output string
There can be multiple abbreviations for the same word.
AUTOMATIC GAIN CONTROL --> AGC
CONTROL --> CTRL
In any case the function should always take the abbreviation which takes the most words.
Example
Map containing following entries:
AUTOMATIC GAIN CONTROL --> AGC
CONTROL --> CTRL
IDENTIFIER --> ID
THE -->
<remove>
. -->
<remove after incl>
: -->
<remove after>
TH -->
<remove before>
Input:
The top control identifier: xyz
Output:
top CTRL ID:
Input:
Lorem impsum TH automatic gain control. This will be deleted
Output:
TH AGC
Code
public final class Shortener {
public static String mappingFile="";
private static final Comparator<String> KEY_COMPARATOR = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
int diff = Integer.valueOf(s2.length()).compareTo(Integer.valueOf(s1.length()));
return diff == 0 ? s1.compareToIgnoreCase(s2) : diff;
}
};
private static Map<String,String> MAPPER;
public static String shortenText(String input) {
StringBuilder result = new StringBuilder(input);
for (Map.Entry<String, String> entry : MAPPER.entrySet()) {
Matcher matcher;
if (entry.getValue().equals("<remove after>") || entry.getValue().equals("<remove after incl>")){
matcher = Pattern.compile("(?i).*" + entry.getKey() + ".*").matcher(result);
}
else matcher = Pattern.compile("(?i)\\b" + entry.getKey() + "\\b").matcher(result);
while (matcher.reset().find()) {
if (entry.getValue().equals("<remove after>")){
result.delete(result.indexOf(entry.getKey())+entry.getKey().length(),result.length());
return result.toString();
}
if (entry.getValue().equals("<remove after incl>")){
result.delete(result.indexOf(entry.getKey()),result.length());
return result.toString();
}
if (entry.getValue().equals("<remove before>")){
result.delete(0,result.indexOf(entry.getKey()));
return result.toString();
}
result.replace(matcher.start(), matcher.end(), entry.getValue());
if (entry.getValue().isEmpty() && result.length() != 0) {
result.deleteCharAt(matcher.start());
}
}
}
return result.toString();
}
public static void importMap() {
FileInputStream fstream;
MAPPER = new TreeMap<String, String>(KEY_COMPARATOR);
try {
if(mappingFile.isEmpty()) {
String fileSperator = System.getProperty("file.separator");
String shortenerConfigPath = System.getProperty("user.dir")+fileSperator+"config"+fileSperator+"shortener.ini";
mappingFile = shortenerConfigPath;
}
fstream = new FileInputStream(mappingFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
while ((strLine = br.readLine()) != null){
String[] arr = strLine.split("\t");
if (arr.length!=2){
System.out.println("Error Shortener import");
}
else {
if (arr[1].equals("<remove>")){
MAPPER.put(arr[0], "");
}
else MAPPER.put(arr[0], arr[1]);
}
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
As you can see I need a different regex pattern for the <remove after>
and <remove after incl>
cases in order to achieve the correct output. For the other cases a regex that looks for words is ok. I feel like the shortenText()
could be improved. Returning the String
early for the special cases seems like it would cause errors but so far that has worked for me.
The Map MAPPER
is populated by reading the contents of a tab delimited file.
<remove after>
or<remove after incl>
. Returning the String early seems suspicious but I have not found any other way to achieve the goal. \$\endgroup\$