boldHighlight method takes text string and highlights in it q keywords via <b></b> tags
colorHighlight method takes text string and highlights int q keywords via <b style='background-color: #color'></b> with 12 alternating colors
String text = "The use of hello as a telephone greeting has been credited to Thomas
Edison; according to one source, he expressed his surprise with a
misheard Hullo. Alexander Graham Bell initially used Ahoy (as used on
ships) as a telephone greeting"
String keywords = "HELLO Surprise"
boldHighlight(text, keywords); // will produce:
The use of <b>hello</b> as a telephone greeting has been credited to Thomas Edison; according to one source, he expressed his <b>surprise</b> with a misheard Hullo. Alexander Graham Bell initially used Ahoy (as used on ships) as a telephone greeting`
colorHighlight(text, keywords); // will produce:
The use of <b style='background-color:#ffff66'>hello</b> as a telephone greeting has been credited to Thomas Edison;>according to one source, he expressed his <b style='background-color:#a0ffff'>surprise</b> with a misheard Hullo. Alexander Graham Bell initially used Ahoy (as used on ships) as a telephone greeting
The question:
is there something I could use like third party library that would do similar job as bellow methods? Or if you look at the code, is there something that can be improved, to make the performance better and/or make it more elegant?`
private static final String[] colors = new String[]{"ffff66", "a0ffff", "99ff99", "ff9999", "ff66ff", "880000", "00aa00", "886800", "004699", "990099", "ffff66", "a0ffff"};
public static String safeCharWithSpace(String input) {
input = input.trim();
return Normalizer.normalize(input.toLowerCase(), Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
.replaceAll("[^\\p{Alnum}]+", " ");
}
private static String prepQuery(String q) {
try {
log.debug("qr encoded: " + q);
q = URLDecoder.decode(q, "UTF-8");
} catch (UnsupportedEncodingException ignore) {
}
log.debug("qr decoded: " + q);
return removeIgnoreCase(q, stopWords);
}
public static String boldHighlight(String text, String q) {
return highlight(text, q, false);
}
public static String colorHighlight(String text, String q) {
return highlight(text, q, true);
}
private static String replaceWord(String text, String keyword, int colorNumber, boolean useColor) {
String color = "";
keyword = safeCharWithSpace(keyword);
if (StringUtils.isNotEmpty(keyword) && !StringUtils.isWhitespace(keyword)) {
if (useColor) color = " style='background-color: " + colors[colorNumber] + "'";
return text.replaceAll("(?i)(" + keyword + ")(?!([^<]+)?>>)", "<b" + color + ">$1</b>");
} else
return text;
}
public static String highlight(String text, String q, boolean useColor) {
String qr = prepQuery(q);
String rtn = null;
int i = 0;
if (qr.startsWith("\"")) {
String keywords = StringUtils.remove(qr, "\"");
rtn = replaceWord(text, keywords, 0, useColor);
} else {
String[] keywords = qr.split("\\s");
for (String keyword : keywords) {
rtn = replaceWord(text, keyword, i, useColor);
if (useColor) {
if (i < 11) i++;
else i = 0;
}
}
}
return rtn;
}
for removal of stop words removeIgnoreCase() in prepQuery() method refer to my other post: Removing strings from another string in java
Wow, well you could go about it a few different ways.
You could call a static method.
i.e.
${statics["java.lang.System"].currentTimeMillis()}
The MVC thing to do would be to do this processing before the template is processed, but I know your just maintaining the code.
It looks like it is just doing several replace all's, so a change to a Java method should work. I have to suggesst you look at the escaping tools Freemarker has.
Freemarker really has great documentation, and built ins cover many situations.
Related
A method replacement replaces all names (from given String a) in [Name] or {Name} brackets, with telephone numbers if [] these brackets, or e-mails if {} these brackets. The address book is represented with array tel, whose elements can be "Tel Name telephoneNumber" or "Mail Name mail". For example if input is: "You can contact jake via phone number [Jake] or via email {Jake}", output should be "You can contact jake via phone number +12345 or via email jake#gmail.com", and tel elements are "Tel Jake +12345" and "Mail Jake jake#gmail.com". If the given name does not exist in address book do nothing with the string. The problem that I have is when it comes to replacing substrings I use method replaceFirst which will replace the first occurrence of the substring that I want to replace.
Maybe the shorter question would be how to replace specific part of string?
public static String replacement(String a, String[] tel) {
for (int i = 0; i<a.length()-1; i++) {
char c = a.charAt(i);
if (c=='[') {
int ind = a.indexOf(']', i);
String name = a.substring(i+1, ind);
for (int j=0; j<tel.length; j++) {
int ind1 = tel[j].indexOf(' ', 4);
String name1 = tel[j].substring(4, ind1);
String p = tel[j].substring(0,3);
String help = "Tel";
int temp = p.compareTo(help);
if (ime.equals(ime1)==true && temp==0) {
String telephone = tel[j].substring(ind1+1, tel[j].length());
a = a.replaceFirst(name, telephone);
}
}
}
if (c=='{') {
int ind = a.indexOf('}', i);
String name = a.substring(i+1, ind);
for (int j=0; j<tel.length; j++) {
int ind1 = tel[j].indexOf(' ', 5);
String name1 = tel[j].substring(5, ind1);
String p = tel[j].substring(0,4);
if (name.equals(name1) && p.compareTo("Mail")==0) {
String mail = tel[j].substring(ind1+1, tel[j].length());
a = a.replaceFirst(name, mail);
}
}
}
}
return a;
}
Main:
String a = "In NY you can contact peter via telephone number [Peter] or e-mail {Peter}. In London you can contact anna via telephone number [Anna] or e-mail {Anna}."
+ "In Chicago you can contact shawn via telephone number [Shawn] or e-mail {Shawn}";
String [] tel = {"Mail Peter peter#gmail.com", "Tel Anna +3456","Tel Shawn +1234", "Mail Shawn shawn#yahoo.com"};
String t = replacement(a,tel);
System.out.println(t);
Console:
In NY you can contact peter via telephone number [peter#gmail.com] or e-mail {peter#gmail.com}.
In London you can contact anna via telephone number [+3456] or e-mail {Anna}.In Chicago you can
contact shawn via telephone number [+1234] or e-mail {shawn#yahoo.com}
Instead of encoding the type of the data (email vs phone number) and the replacement key into strings, I would put the data into separate variables and ues data structures like Map:
Map<String, String> tel = Map.of("Anna", "+3456", "Shawn", "+1234");
Map<String, String> mail = Map.of("Peter", "peter#gmail.com", "Shawn", "shawn#yahoo.com");
String t = replacement(a, tel, mail);
The replacement function could use a regular expression to find the substrings that match the key words you want to replace [something] and {something}. It would check which one it found, and add a replacement using the telephone or email it finds in the map data structure.
private static String replacement(String a, Map<String, String> tel, Map<String, String> mail) {
Pattern compile = Pattern.compile("\\{(.*?)\\}|\\[(.*?)\\]");
Matcher matcher = compile.matcher(a);
StringBuilder sb = new StringBuilder();
// Find substrings matching {something} and [something]
while (matcher.find()) {
String matched = matcher.group(0);
// Which was it, { or [ ?
if (matched.charAt(0) == '{') {
// Email. Replace from "mail"
String emailAddress = mail.getOrDefault(matcher.group(1), matched);
matcher.appendReplacement(sb, emailAddress);
} else if (matched.charAt(0) == '[') {
// Telephone. Replace from "tel"
String phoneNumber = tel.getOrDefault(matcher.group(2), matched);
matcher.appendReplacement(sb, phoneNumber);
}
}
matcher.appendTail(sb);
return sb.toString();
}
Handling of strings in a specified format is done best using regular expressions. You define a specified pattern and after you find a part matching your pattern, you can replace it or analyze further.
It's best to write your code to make it easily extensible. For example - if a new contact form is added (home address, fax, business phone number), it should be easy to handle it in the code. Your solution makes it harder to resolve such problems as a whole new if branch is required and it's easy to make a mistake, it also makes the code less readable.
When dealing with a kind of dictionary (like your input String array), it's worth using a Map as it makes the processing faster and the code more readable. When a constant values are present, it's worth to define them too - as constants or enum values. Also - Java allows for writing more functional and more readable, functional-style code instead of nested for-eaches - it's worth using those features (JDK8+).
Please, find the code snippet below and a whole project with tests comparing your solution to mine on GitHub - you can view it there or clone the repository and verify the code yourself:
// we can simply add new contact types and their matchers using the constant below
private static final Map<Pattern, ContactType> CONTACT_PATTERNS = Map.of(
Pattern.compile("\\[(\\S+)]"), ContactType.TEL,
Pattern.compile("\\{(\\S+)}"), ContactType.MAIL
);
#Override
public String replace(String input, String[] dictionary) {
// we're mapping the dictionary to make it easier to use and more readable (also in debugging)
Map<ContactType, Map<String, String>> contactTypeToNameToValue =
Arrays.stream(dictionary)
.map(entry -> entry.split(" ")) // dictionary entry is split by ' ' character
.collect(groupingBy(entry -> ContactType.fromString(entry[0]), // first split part is the contact type
toMap(entry -> entry[1], // second part is the person's name
entry -> entry[2]))); // third part is the contact value
String output = input;
for (Map.Entry<Pattern, ContactType> entry : CONTACT_PATTERNS.entrySet()) {
Pattern pattern = entry.getKey();
ContactType contactType = entry.getValue();
output = pattern.matcher(output)
.replaceAll(matchResult -> {
String name = matchResult.group(1);
// we search our dictionary and get value from it or get the original value if nothing matches given name
return Optional.ofNullable(contactTypeToNameToValue.get(contactType))
.map(nameToValue -> nameToValue.get(name))
.orElseGet(matchResult::group);
});
}
return output;
}
public enum ContactType {
TEL,
MAIL;
private static ContactType fromString(String value) {
return Arrays.stream(values())
.filter(enumValue -> enumValue.name().equalsIgnoreCase(value))
.findFirst()
.orElseThrow(RuntimeException::new);
}
}
This question already has an answer here:
How to parse field name with dash in snakeyaml?
(1 answer)
Closed 3 years ago.
I'm attempting to dump a YAML File to a Java Class using SnakeYAML, but the field has hyphens in the name, and java variables cannot contain -.
I've seen this answer regarding the subject, but there is no explanation as to what is happening or what the method toCameName() does.
Yaml File
field-with-hyphen: 1
Goal
public int fieldwithhypehen;
or whatever makes it so I can dump it.
Thanks to Clashsoft for pointing me in the right direction. I was able to do some further research and construct the following method that transfers values with spaces and hyphens to camelCase.
field-with-hyphens and spaces turns into fieldWithHyphensAndSpaces
public class CamelCase {
public static String camelize(String input) {
for (int i = 0; i < input.length(); i++) {
if(input.substring(i, i+1).equals("-")) {
input.replace("-", "");
input = input.substring(0, i) + input.substring(i+1, i+2).toUpperCase() + input.substring(i+2);
}
if(input.substring(i, i+1).equals(" ")) {
input.replace(" ", "");
input = input.substring(0, i) + input.substring(i+1, i+2).toUpperCase() + input.substring(i+2);
}
}
return input;
}
}
and implemented with SnakeYAML Parser (i tested it as well)
Constructor c = new Constructor(map);
c.setPropertyUtils(new PropertyUtils() {
#Override
public Property getProperty(Class<? extends Object> type, String name){
if ( name.indexOf('-') > -1 ) {
name = CamelCase.camelize(name);
}
return super.getProperty(type, name);
}
});
parser = new Yaml(c);
configFile = new File(FileConstants.getConfigDir() + relativePath);
}
public class Main{
public static void main(String[] args)
{
String a = "PORT:AXN,0,10;BGT,20,30;CXZ,10,30|BENCH:AXN,50,10;BGT,30,30;DFG,30,20;XYZ,0,10";
Port port = new Port();
Port bench = new Port();
}
}
public class Port{
List<String> name = new ArrayList<String>();
List<Integer> qty = new ArrayList<Integer>();
List<Integer> price = new ArrayList<Integer>();
}
I want to go through the string and store the information in these objects so
port object gets:
AXN,BGT,CXZ in the name list
0,20,10 in the qty list
10,30,30 in the price list
And similarly for the bench object using the bench data in the string.
In the string, there can be any number of tuples in the string for each. eg. port can have 5 sets, bench can have 8. And the codes for each (the name) have to be 3 alpha characters long but can be anything.
How can I go about doing this? The only thing I can think of is using the split method somehow but am having a hard time working out exactly how to use it? Any help would be great! thanks
You can use split with some loops like this :
String a ="PORT:AXN,0,10;BGT,20,30;CXZ,10,30|BENCH:AXN,50,10;BGT,30,30;DFG,30,20;XYZ,0,10";
Port port = new Port();
String[] tuples = a.split("\\|");
//Split with | to get the tuples
//PORT:AXN,0,10;BGT,20,30;CXZ,10,30
//BENCH:AXN,50,10;BGT,30,30;DFG,30,20;XYZ,0,10
for(String tuple : tuples){
String[] objects = tuple.split(";");//split each tuple with ; to get the information
//PORT:AXN,0,10
//BGT,20,30
//CXZ,10,30
for(String obj : objects){
//split with , to get the three properties(name, qty, price)
String[] spl = obj.replaceAll("(.*?):(.*?)", "$2").split(",");
port.name.add(spl[0]);//name value
port.qty.add(Integer.parseInt(spl[1]));//qty value
port.price.add(Integer.parseInt(spl[2]));//price value
}
}
Classes
As I suggested, I think modifying a bit your Port class and creating a PortObject class could improve readibility. Basically:
A port has a name and a list of port objects
A port object has a name, a quantity and a price:
For each class, I'll create two constructor:
constructor which takes all attributes and assign
constructor which build object from a raw String input
Classes are private static and don't have getter because I put everything in the Main.java but this is not a good practice!
Port class
private static class Port {
final String name;
final List<PortObject> portObjects;
// format is PORT:AXN,0,10;BGT,20,30;CXZ,10,30
public Port(String input) {
String[] split = input.split(":");
name = split[0];
this.portObjects = Pattern.compile(";").splitAsStream(split[1])
.map(PortObject::new)
.collect(Collectors.toList());
}
public Port(String name, List<PortObject> portObjects) {
this.name = name;
this.portObjects = portObjects;
}
#Override
public String toString() {
return "Port:" + name + " " + portObjects.toString();
}
}
Port object class
private static class PortObject {
final String name;
final int qty;
final int price;
// format is AXN,0,10
public PortObject(String input) {
String[] split = input.split(",");
name = split[0];
qty = Integer.parseInt(split[1]);
price = Integer.parseInt(split[2]);
}
public PortObject(String name, int qty, int price) {
this.name = name;
this.qty = qty;
this.price = price;
}
#Override
public String toString() {
return name + ":" + qty + ":" + price;
}
}
Not a so good idea: Regex
When it's about matching a pattern, one may think about Regex. Regex will require the second constructor (the one which does not take a raw String input as argument). I'm not a Regex expert so I'll do a simple way:
[^\\|]+ is the equivalent of String.split("\\|")
(\\w+):(.*) will match the port name and the list of port objects. This list will be processed by the next regex:
(\\w{3}),(\\d+),(\\d+);? will match the three-characters port object name, ask for a digit-only quantity and a digit-only price followed by an optional semi-colon (optional because the last port object does not have semi-colon)
Put in code, it looks like as follow:
public static void main(String[] args) throws IOException {
// the input
String a = "PORT:AXN,0,10;BGT,20,30;CXZ,10,30|BENCH:AXN,50,10;BGT,30,30;DFG,30,20;XYZ,0,10";
// Option 1: Regex
List<Port> portList1 = new ArrayList<>();
// initialise regex
String splitRegex = "[^\\|]+"; // Regex 1.
String portRegex = "(\\w+):(.*)"; // Regex 2.
String portObjectRegex = "(\\w{3}),(\\d+),(\\d+);?"; // Regex 3.
Pattern patternSplit = Pattern.compile(splitRegex);
Pattern patternPort = Pattern.compile(portRegex);
Pattern patternPortObject = Pattern.compile(portObjectRegex);
Matcher matcherSplit = patternSplit.matcher(a);
Matcher matcherPort;
Matcher matcherPortObject;
// look for each port
while (matcherSplit.find()) {
String portSplit = matcherSplit.group();
matcherPort = patternPort.matcher(portSplit);
while (matcherPort.find()) {
// keep the port name
String name = matcherPort.group(1);
List<PortObject> portObjectList = new ArrayList<>();
matcherPortObject = patternPortObject.matcher(matcherPort.group(2));
// look for each port object
while (matcherPortObject.find()) {
String poName = matcherPortObject.group(1);
int poQty = Integer.parseInt(matcherPortObject.group(2));
int poPrice = Integer.parseInt(matcherPortObject.group(3));
portObjectList.add(new PortObject(poName, poQty, poPrice));
}
portList1.add(new Port(name, portObjectList));
}
}
// Print
System.out.println("PortList1:\n" + portList1 + "\n");
}
The output is
PortList1:
[Port:PORT [AXN:0:10, BGT:20:30, CXZ:10:30], Port:BENCH [AXN:50:10, BGT:30:30, DFG:30:20, XYZ:0:10]]
Most likely a better idea: Split + Stream
Honestly speaking, I didn't know that split can directly be turned into a Stream. It basically leverages the Pattern.compile(yourRegex).splitAsStream(yourInput). As I said, this is a long split way but as the split are dispatched in Port constructor and PortObject constructor, it makes it easier to read:
Put in code, it is much shorter:
public static void main(String[] args) throws IOException {
// the input
String a = "PORT:AXN,0,10;BGT,20,30;CXZ,10,30|BENCH:AXN,50,10;BGT,30,30;DFG,30,20;XYZ,0,10";
// Option 2: Split with Stream:
List<Port> portList2 = Pattern.compile("\\|").splitAsStream(a)
.map(Port::new)
.collect(Collectors.toList());
// Print
System.out.println("PortList2:\n" + portList2 + "\n");
}
Obviously, the output is the same:
PortList2:
[Port:PORT [AXN:0:10, BGT:20:30, CXZ:10:30], Port:BENCH [AXN:50:10, BGT:30:30, DFG:30:20, XYZ:0:10]]
I've posted about letters earlier, but this is an another topic, I have a json response that contain 2 objects, from and to , from is what to change, and to is what it will be changed to .
My code is :
// for example, the EnteredText is "ab b test a b" .
EnteredString = EnteredText.getText().toString();
for (int i = 0; i < m_jArry.length(); i++) {
JSONObject jo_inside = m_jArry.getJSONObject(i);
String Original = jo_inside.getString("from");
String To = jo_inside.getString("to");
if(isMethodConvertingIn){
EnteredString = EnteredString.replace(" ","_");
EnteredString = EnteredString.replace(Original,To + " ");
} else {
EnteredString = EnteredString.replace("_"," ");
EnteredString = EnteredString.replace(To + " ", Original);
}
}
LoadingProgress.setVisibility(View.GONE);
SetResultText(EnteredString);
ShowResultCardView();
For example, the json response is :
{
"Response":[
{"from":"a","to":"bhduh"},{"from":"b","to":"eieja"},{"from":"tes","to":"neesj"}
]
}
String.replace() method won't work here, because first it will replace a to bhduh, then b to eieja, BUT here's the problem, it will convert b in bhduh to eieja, which i don't want to.
I want to perfectly convert the letters and "words" in the String according the Json, but that what i'm failing at .
New Code :
if(m_jArry.length() > 0){
HashMap<String, String> m_li;
EnteredString = EnteredText.getText().toString();
Log.i("TestAf_","Before Converting: " + EnteredString);
HashMap<String,String> replacements = new HashMap<String,String>();
for (int i = 0; i < m_jArry.length(); i++) {
JSONObject jo_inside = m_jArry.getJSONObject(i);
String Original = jo_inside.getString("from");
String To = jo_inside.getString("to");
if(isMethodConvertingIn){
//EnteredString = EnteredString.replace(" ","_");
replacements.put(Original,To);
Log.i("TestAf_","From: " + Original + " - To: " + To + " - Loop: " + i);
//EnteredString = EnteredString.replace(" ","_");
//EnteredString = EnteredString.replace(Original,To + " ");
} else {
EnteredString = EnteredString.replace("_"," ");
EnteredString = EnteredString.replace("'" + To + "'", Original);
}
}
Log.i("TestAf_","After Converting: " + replaceTokens(EnteredString,replacements));
// Replace Logic Here
// When Finish, Do :
LoadingProgress.setVisibility(View.GONE);
SetResultText(replaceTokens(EnteredString,replacements));
ShowResultCardView();
Output :
10-10 19:51:19.757 12113-12113/? I/TestAf_: Before Converting: ab a ba
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: a - To: bhduh - Loop: 0
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: b - To: eieja - Loop: 1
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: o - To: neesj - Loop: 2
10-10 19:51:19.758 12113-12113/? I/TestAf_: After Converting: ab a ba
You question would be clearer if you gave the expected output for the function.
Assuming it is: ab b test a b >>>> bhduheieja eieja neesjt bhduh eieja
then see the following, the key point in the Javadoc being "This will not repeat"
http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#replaceEach(java.lang.String,%20java.lang.String[],%20java.lang.String[])
Replaces all occurrences of Strings within another String.
A null reference passed to this method is a no-op, or if any "search
string" or "string to replace" is null, that replace will be ignored.
This will not repeat. For repeating replaces, call the overloaded
method.
Example 1
import org.apache.commons.lang3.StringUtils;
public class StringReplacer {
public static void main(String[] args) {
String input = "ab b test a b";
String output = StringUtils.replaceEach(input, new String[] { "a", "b", "tes" },
new String[] { "bhduh", "eieja", "neesj" });
System.out.println(input + " >>>> " + output);
}
}
Example 2
import org.apache.commons.lang3.StringUtils;
public class StringReplacer {
public static void main(String[] args) {
String input = "this is a test string with foo";
String output = StringUtils.replaceEach(input, new String[] { "a", "foo" },
new String[] { "foo", "bar"});
System.out.println(input + " >>>> " + output);
}
}
Try following:
Solution 1:
Traverse the String characters one by one and move the new String to a new StringBuffer or StringBuilder, then call toString() to get the result. This will need you to implement string matching algorithm.
Solution 2 (Using Regex):
For this, you must know the domain of your string. For example, it is [a-zA-Z] then other arbitrary characters (not part of domain) can be used for intermediate step. First replace the actual characters with arbitrary one then arbitrary ones with the target. In example below, [!##] are the arbitrary characters. These can be any random \uxxxx value as well.
String input = "a-b-c";
String output = input.replaceAll("[a]", "!").replaceAll("[b]", "#").replaceAll("[c]", "#");
output = output.replaceAll("[!]", "bcd").replaceAll("[#]", "cde").replaceAll("[#]", "def");
System.out.println("input: " + input);
System.out.println("Expected: bcd-cde-def");
System.out.println("Actual: " + output);
Your issue is quite common. To sum things up :
String test = "this is a test string with foo";
System.out.println(test.replace("a", "foo").replace("foo", "bar"));
Gives : this is bar test string with bar
Expected by you : this is foo test string with bar
You can use StrSubstitutor from Apache Commons Lang
But first you will have to inject placeholders in your string :
String test = "this is a test string with foo";
Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("a", "foo");
valuesMap.put("foo", "bar");
String testWithPlaceholder = test;
// Preparing the placeholders
for (String value : valuesMap.keySet())
{
testWithPlaceholder = testWithPlaceholder.replace(value, "${"+value+"}");
}
And then, use StrSubstitutor
System.out.println(StrSubstitutor.replace(testWithPlaceholder, valuesMap));
It gives : this is foo test string with bar
Here is an method which is strictly just Java. I tried not to use any Java 8 methods here.
public static String translate(final String str, List<String> from, List<String> to, int index) {
StringBuilder components = new StringBuilder();
String token, replace;
int p;
if (index < from.size()) {
token = from.get(index);
replace = to.get(index);
p = 0;
for (int i = str.indexOf(token, p); i != -1; i = str.indexOf(token, p)) {
if (i != p) {
components.append(translate(str.substring(p, i), from, to, index + 1));
}
components.append(replace);
p = i + token.length();
}
return components.append(translate(str.substring(p), from, to, index + 1)).toString();
}
return str;
}
public static String translate(final String str, List<String> from, List<String> to) {
if (null == str) {
return null;
}
return translate(str, from, to, 0);
}
Sample test program
public static void main(String []args) {
String EnteredString = "aa hjkyu batesh a";
List<String> from = new ArrayList<>(Arrays.asList("a", "b", "tes"));
List<String> to = new ArrayList<>(Arrays.asList("bhduh", "eieja", "neesj"));
System.out.println(translate(EnteredString, from, to));
}
Output:
bhduhbhduh hjkyu eiejabhduhneesjh bhduh
Explaination
The algorithm is recursive, and it simply does the following
If a pattern found in the string matches a pattern in the from list
if there is any string before that pattern, apply the algorithm to that string
replace the found pattern with the corresponding pattern in the to list
append the replacement to the new string
discard the pattern in the from list and repeat the algorithm for the rest of the string
Otherwise append the rest of the string to the new string
You could use split like:
String[] pieces = jsonResponse.split("},{");
then you just parse the from and to in each piece and apply them with replace() then put the string back together again. (and please get your capitalization of your variables/methods right - makes it very hard to read the way you have it)
Apache Commons StringUtils::replaceEach does this.
String[] froms = new String[] {"a", "b"};
String[] tos = new String[] {"b","c"};
String result = StringUtils.replaceEach("ab", froms, tos);
// result is "bc"
Why not keep it very simple (if the JSON is always in same format, EG: from the same system). Instead of replacing from with to, replace the entire markup:
replace "from":"*from*" with "from":"*to*"
Why not just change the actual "to" and "from" labels? That way, you don't run into a situation where "bhudh" becomes "eieja". Just do a string replace on "from" and "to".
I want to remove the following words from end of String ‘PTE’, ‘LTD’, ‘PRIVATE’ and ‘LIMITED’
i tried the code but then i stuck. i tried this
String[] str = {"PTE", "LTD", "PRIVATE", "LIMITED"};
String company = "Basit LTD";
for(int i=0;i<str.length;i++) {
if (company.endsWith(str[i])) {
int position = company.lastIndexOf(str[i]);
company = company.substring(0, position);
}
}
System.out.println(company.replaceAll("\\s",""));
It worked. But suppose the company is Basit LIMITED PRIVATE LTD PTE or Basit LIMITED PRIVATE PTE LTD or any combination of four words in the end. Then the above code just remove the last name i.e., PTE or PRIVATE and so on, and the output is BasitLIMITEDPRIVATELTD.
I want output to be just Basit
How can i do it?
Thanks
---------------Edit---
Please note here the company name is just an example, it is not necessary that it is always the same. may be i have name like
String company = "Masood LIMITED LTD PTE PRIVATE"
or any name that can have the above mentioned words at the end.
Thanks
You can do this in single line. no need to loop through. just use String#replaceAll(regex, str).
company = company.replaceAll("PTE$*?|LTD$*?|PRIVATE$*?|LIMITED$*?","");
If you place the unwanted words in the map it will be ommitted in the resultant string
HashMap map = new HashMap();
map.put("PTE", "");
map.put("LTD", "");
map.put("PRIVATE", "");
map.put("LIMITED", "");
String company = "Basit LTD PRIVATE PTE";
String words[] = company.split(" ");
String resultantStr = "";
for(int k = 0; k < words.length; k++){
if(map.get(words[k]) == null) {
resultantStr += words[k] + " ";
}
}
resultantStr = resultantStr.trim();
System.out.println(" Trimmed String: "+ resultantStr);
If you want to remove these suffixes only at the end of the string, then you could introduce a while loop:
String[] str = {"PTE", "LTD", "PRIVATE", "LIMITED"};
boolean foundSuffix = true;
String company = "Basit LTD";
while (foundSuffix) {
foundSuffix = false;
for(int i=0;i<str.length;i++) {
if (company.endsWith(str[i])) {
foundSuffix = true;
int position = company.lastIndexOf(str[i]);
company = company.substring(0, position);
}
}
}
System.out.println(company.replaceAll("\\s",""));
If you don't mind transforming PTE Basit LIMITED INC to Basit (and also remove the first PTE), then replaceAll should work, as explained by others.
I was trying to do exactly same thing for one of my projects. I wrote this code few days earlier. Now I was exactly trying to find a much better way to do it, that's how I found this Question. But after seeing other answers I decided to share my version of the code.
Collection<String> stopWordSet = Arrays.asList("PTE", "LTD", "PRIVATE", "LIMITED");
String company = "Basit LTD"; //Or Anything
String[] tokens = company.split("[\#\]\\\_\^\[\"\#\ \!\&\'\`\$\%\*\+\(\)\.\/\,\-\;\~\:\}\|\{\?\>\=\<]+");
Stack<String> tokenStack = new Stack<>();
tokenStack.addAll(Arrays.asList(tokens));
while (!tokenStack.isEmpty()) {
String token = tokenStack.peek();
if (stopWordSet.contains(token))
tokenStack.pop();
else
break;
}
String formattedCompanyName = StringUtils.join(tokenStack.toArray());
Try this :
public static void main(String a[]) {
String[] str = {"PTE", "LTD", "PRIVATE", "LIMITED"};
String company = "Basit LIMITED PRIVATE LTD PTE";
for(int i=0;i<str.length;i++) {
company = company.replaceAll(str[i], "");
}
System.out.println(company.replaceAll("\\s",""));
}
All you need is to use trim() and call your function recursively, Or each time you remove a sub string from the end, reset your i to 0.
public class StringMatchRemove {
public static void main(String[] args) {
String str="my name is noorus khan";
String search="noorus";
String newString="";
String word=str.replace(search," ");
StringTokenizer st = new StringTokenizer(word," ");
while(st.hasMoreTokens())
{
newString = newString + st.nextToken() + " ";
}
System.out.println(newString);
}
first using the replace method we get word=my name is ..... khan (Note: here(.) represents the space). Now we should have to remove these spaces for that we are creating a new string adding all the token simply.
Output: my name is khan