How to remove duplicate values in string which has delimiters - java

I have string with value as ||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||
I am trying to write code which should remove duplicates and return the unique values retaining the demiliters like this ||HelpDesk||IT Staff||Admin||Audit||
My code is using HashSet to remove duplicates but the problem is it is removing delimiters. How can I retain delimiters by removing duplicate values only.
Below is my code after removing duplicates and adding back delimiters. But not sure if there is easy way of doing this.
public static void main(String[] args) {
TestDuplicates testDuplicates = new TestDuplicates();
String bRole = "||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||";
List<String> listWithoutDuplicates = new ArrayList<String>();
String noDup = "";
List<String> splittedStringList =
new ArrayList<String>();
SplitOperations splitOperations =
new SplitOperations();
splittedStringList =
splitOperations.splitString(bRole);
for (int i = 0; i < splittedStringList.size(); i++) {
HashSet<String> listToSet = new HashSet<String>(splittedStringList);
listWithoutDuplicates = new ArrayList<String>(listToSet);
}
for(int i=0;i<listWithoutDuplicates.size();i++){
noDup = noDup + "||"+listWithoutDuplicates.get(i);
System.out.println(listWithoutDuplicates.get(i));
}
System.out.println("No Duplicate is::"+ noDup+"||");
}
Thanks

You could use a LinkedHashSet to preserve insertion order. Once you splitted the String by "||" just add the delimiters when constructing back the String.
String s = "||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||";
Set<String> set = new LinkedHashSet<>(Arrays.asList(s.split(Pattern.quote("||"))));
String noDup = "||";
for(String st : set) {
if(st.isEmpty()) continue;
noDup += st+"||";
}
Or using the new java 8 Stream API :
String noDup = "||"+
Arrays.stream(s.split(Pattern.quote("||")))
.distinct()
.filter(st -> !st.isEmpty()) //we need to remove the empty String produced by the split
.collect(Collectors.joining("||"))+"||";
Both approaches yield the same result (||HelpDesk||IT Staff||Admin||Audit||).

public String removeDublicate () {
String str = "||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||";
String split[] = str.split("\\|\\|");
String newStr = "";
for (String s : split) {
if (!s.isEmpty() && !newStr.contains(s)) {
newStr += "||" + s;
}
}
newStr += "||";
return newStr;
}
Something like that? str could be an argument.
Edit #1
If you want to get rid of && !newStr.contains(s) you can use a HashSet<String> instead. I think that is overkill however. .contains(s) will do the trick when the string is small such as this.

This should work, also it will maintain sequence of elements if you want. Note that I have not written code to put delimiters again.
public static void main(String s[]){
String a = "||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||";
a = a.replaceAll("\\|\\|",",");
String arr[] = a.split(",");
//linked hash set in case you want to maintain the sequence of elements
Set<String> set = new LinkedHashSet<String>(Arrays.asList(arr));
set.remove("");
System.out.println(set);
//Iterate through the set and put your delimiters here again
}

Using Guava lib it's a one liner:
Joiner.on("||").skipNulls(Splitter.on("||").trimResults().split(<target_string>);)
Here is my attempt at it:
import java.util.*;
public class Seperator {
public static void main(String[] args) {
String bRole = "||HelpDesk||IT Staff||IT Staff||Admin||Audit||HelpDesk||";
List<String> listWithoutDuplicates = new ArrayList<String>();
String noDup = "";
List<String> splittedStringList = new ArrayList<String>();
splittedStringList = Arrays.asList(bRole.split("\\|\\|"));
LinkedHashSet<String> listToSet = new LinkedHashSet<String>(splittedStringList);
noDup = Seperator.join(listToSet, "||");
System.out.println("No Duplicate is::"+ noDup+"||");
}
public static String join(Set<String> set, String sep) {
String result = null;
if(set != null) {
StringBuilder sb = new StringBuilder();
Iterator<String> it = set.iterator();
if(it.hasNext()) {
sb.append(it.next());
}
while(it.hasNext()) {
sb.append(sep).append(it.next());
}
result = sb.toString();
}
return result;
}
}
LinkedHashSet are mainly used to preserve the order and ofcourse get uniques elements. Joining is pretty standard, but we can use Google's Guava Library also (Joiner):
So, instead of Seperator.join(listToSet, "||");
You'll have: Joiner.on("||").join(listToSet);

Here's a regex-based one liner:
str = str.replaceAll("(\\|[^|]+)(?=.*\\1\\|)", "");
This works by replacing every term that is followed by itself somewhere ahead via a look ahead assertion that uses a back reference.
Here's a non-regex java 8 one liner:
Arrays.stream(str.substring(1).split("[|]")).distinct().collect(Collectors.joining("|", "|", "|"));

Related

How to replace specific characters with corresponding characters in java? [duplicate]

This question already has answers here:
Most efficient way to use replace multiple words in a string [duplicate]
(4 answers)
Closed 5 years ago.
I want to do something like this: Replace all ck with k and all dd with wr and all f with m and 10 more replacements like this.
I can do it with replace("ck","k").replace("dd","wr")and so on, but it seams silly and it is slow. Is there any function in java that does something like this?
for example replace(string,stringArray1, stringArray2);
Use an appendReplacement loop.
Here is a general purpose way to do it:
private static String replace(String input, Map<String, String> mappings) {
StringBuffer buf = new StringBuffer();
Matcher m = Pattern.compile(toRegex(mappings.keySet())).matcher(input);
while (m.find())
m.appendReplacement(buf, Matcher.quoteReplacement(mappings.get(m.group())));
return m.appendTail(buf).toString();
}
private static String toRegex(Collection<String> keys) {
return keys.stream().map(Pattern::quote).collect(Collectors.joining("|"));
}
If you're not using Java 8+, the second method would be:
private static String toRegex(Collection<String> keys) {
StringBuilder regex = new StringBuilder();
for (String key : keys) {
if (regex.length() != 0)
regex.append("|");
regex.append(Pattern.quote(key));
}
return regex.toString();
}
Test code
Map<String, String> mappings = new HashMap<>();
mappings.put("ck","k");
mappings.put("dd","wr");
mappings.put("f", "m");
System.out.println(replace("odd flock", mappings)); // prints: owr mlok
See IDEONE for running version.
Map<String, String> replacementMap = new HashMap<String, String>();
replacementMap.put("ck", "k");
replacementMap.put("dd", "wr");
replacementMap.put("f", "m");
// ...
String resultStr = "Abck fdddk wr fmck"; // whatever string to process
StringBuilder builder = new StringBuilder(resultStr); // wrap it in builder
Iterator<String> iterator = replacementMap.keySet().iterator();
while (iterator.hasNext()) {
String strToReplace = iterator.next();
replaceAll(builder, strToReplace, replacementMap.get(strToReplace));
}
System.out.println("Result is: " + builder.toString());
public static void replaceAll(StringBuilder builder, String from, String to) {
int index = builder.indexOf(from);
while (index != -1) {
builder.replace(index, index + from.length(), to);
index += to.length(); // Move to the end of the replacement
index = builder.indexOf(from, index);
}
}
The replaceAll() method was borrowed from this Jon Skeet's answer
Alternative to replaceAll() int his example is to use apache commons library, there is StrBuilder class which provides replaceAll() method. see this answer

Extracting strings that contains particular words

This code can extract sentences that contain a particular word. The problem is if I want to extract several sentences based on different words I must copy it several times. Is there a way of doing this with several words? possibly feeding an array to it?
String o = "Trying to extract this string. And also the one next to it.";
String[] sent = o.split("\\.");
List<String> output = new ArrayList<String>();
for (String sentence : sent) {
if (sentence.contains("this")) {
output.add(sentence);
}
}
System.out.println(">>output=" + output);
You can try this:
String o = "Trying to extract this string. And also the one next to it.";
String[] sent = o.split("\\.");
List<String> keyList = new ArrayList<String>();
keyList.add("this");
keyList.add("these");
keyList.add("that");
List<String> output = new ArrayList<String>();
for (String sentence : sent) {
for (String key : keyList) {
if (sentence.contains(key)) {
output.add(sentence);
break;
}
}
}
System.out.println(">>output=" + output);
String sentence = "First String. Second Int. Third String. Fourth Array. Fifth Double. Sixth Boolean. Seventh String";
List<String> output = new ArrayList<String>();
for(String each: sentence.split("\\.")){
if(inKeyword(each)) output.add(each);
}
System.out.println(output);
Helper Function:
public static Boolean inKeyword(String currentSentence){
String[] keyword = {"int", "double"};
for(String each: keyword){
if(currentSentence.toLowerCase().contains(each)) return true;
}
return false;
}
If you have a list of words to filter for called filter and an array of sentences you could use Collections.disjoint to compare if the words of that sentence does not overlap with the words to filter for. Sadly, this does not work if you filter for "However" and your sentence contains "However,".
Collection<String> filter = /**/;
String[] sentences = /**/;
List<String> result = new ArrayList();
for(String sentence : sentences) {
Collection<String> words = Arrays.asList(sentence.split(" "));
// If they do not not overlap, they overlap
if (!Collections.disjoint(words, filter)) {
result.add(sentence);
}
}
You can use String.matches as follows.
String sentence = ...;
if (sentence.matches(".*(you|can|use).*")) { // Or:
if (sentence.matches(".*\\b(you|can|use)\\b.*")) { // With word boundaries
if (sentence.matches("(?i).*(you|can|use).*")) { // Case insensitive ("You")
In java 8 the following variations might do:
String pattern = ".*(you|can|use).*";
String pattern = new StringJoiner("|", ".*(", ").*)
.add("you")
.add("can")
.add("use")
.toString();
// Or a stream on the words with a joining collector
Arrays.stream(o.split("\\.\\s*"))
filter(sentence -> sentence.matches(pattern))
forEach(System.out::println);
With streams (splitting into sentences and words):
String o = "Trying to extract this string. And also the one next to it.";
Set<String> words = new HashSet<>(Arrays.asList("this", "also"));
List<String> output = Arrays.stream(o.split("\\.")).filter(
sentence -> Arrays.stream(sentence.split("\\s")).anyMatch(
word -> words.contains(word)
)
).collect(Collectors.toList());
System.out.println(">>output=" + output);

Any shortest method to get RHS values in the string with comma separated

This is my String
String str = "fus=""192.10.136.111"""," ful=""333333"""," fui=""7b7b7b40000000010000012e55192ab8""", fuc=1, fuq=3, fut=2015-03-30 16:21:36, fud=1, fss=3, fst=2," fsi=""302""", fso=0, fsa=0, fsr=2, cuc=1".
I need only the RHS values without double quotes with comma seperated. For example
192.10.136.111,333333,7b7b7b40000000010000012e55192ab8,1,3,2015-03-30 16:21:36,1,3,2,302,0,0,2,1
The logic should be generic
If you have a string like below (which is basically a CSV of key-value pair)
String str = "fus=\"192.168.1.1\",fus1=\"333333\"";
You can use below code
List<String> values = new ArrayList<>();
String [] keyValuePairs = str.split(",");
for(String keyValuePair : keyValuePairs) {
String [] keyValue = keyValuePair.split("=");
values.add(keyValue[1]);
}
Seeing that this is only your second question, you need to get into a habit of providing MCVE. You posted your problem, but you didn't post an attempt or even an explanation of an attempt.
Having said that, after escaping all of the quotations in your string, you could try simple string manipulations.
public static void main(String[] args) throws Exception {
String str = "fus=\"\"192.10.136.111\"\"\",\" ful=\"\"333333\"\"\",\" fui=\"\"7b7b7b40000000010000012e55192ab8\"\"\", fuc=1, fuq=3, fut=2015-03-30 16:21:36, fud=1, fss=3, fst=2,\" fsi=\"\"302\"\"\", fso=0, fsa=0, fsr=2, cuc=1";
String[] pieces = str.split(",");
for (int i = 0; i < pieces.length; i++) {
pieces[i] = pieces[i].substring(pieces[i].indexOf("=") + 1).replaceAll("\"", "");
}
System.out.println(String.join(",", pieces));
}
Results:

How can i extract a specific item with split function

It's possible to extract a specific item in String with split function
example:
offers/BESTOFFERS/FRTNE/FRPAR/2015-01-05?passengers=STANDARD:1&returnDate=2015-01-12&maxVia=0&withThac=false
i want to extract just returnDate
ouptut why i want:
2015-01-12
OR
i want to extract just passengers
ouptut why i want:
STANDARD:1
If you really need to stick on the split method you could solve it for example like this
String str = "offers/BESTOFFERS/FRTNE/FRPAR/2015-01-05?passengers=STANDARD:1&returnDate=2015-01-12&maxVia=0&withThac=false";
int paramDelim = str.indexOf('?');
String parmeters = str.substring(paramDelim + 1, str.length());
String[] parts = parmeters.split("[&=]");
System.out.println("parts = " + Arrays.toString(parts));
parts contain the paramer names (odd entries) and the values (even entries).
If you don't need to stick on the split method try one of the proposed URL parser solutions.
You can also try the below approach of using HashMap
void populateMap()
{
Map<String, String> myMap = new HashMap<String, String>();
String uri = "offers/BESTOFFERS/FRTNE/FRPAR/2015-01-05?passengers=STANDARD:1&returnDate=2015-01-12&maxVia=0&withThac=false";
int len = uri.indexOf('?');
String input = str.substring(len + 1, uri.length());
for(String retVal : input.split("&")
{
String[] innerRet = retVal.split(":");
myMap.put(innerRet[0],innerRet[1]);
}
}
String retValue (String key)
{
return myMap.get(key);
}
String str = "offers/BESTOFFERS/FRTNE/FRPAR/2015-01-05?passengers=STANDARD:1&returnDate=2015-01-12&maxVia=0&withThac=false";
String returnDate = str.split("&")[1].replaceAll
("returnDate=","").trim();
String passengers= str.split("?")[1].split("&")[0].replaceAll
("passengers=","").trim();

Java String Method

I have comma separated string variable like:
String doctors = "doc_vijayan,doc_zubair,doc_Raja"
But i want to delete "doc_" from the above String and First Letter should display in capital. I need output like this:
String doctors1 = "Vijayan, Zubair, Raja"
How to do that?
You can try that :
public String splitDoctors(String doctorsString){
String[] doctors = doctorsString.split(",");
boolean isFirst = true;
StringBuilder sb = new StringBuilder();
for(String doctor : doctors){
if(!isFirst){
sb.append(", ");
}else{
isFirst = false;
}
sb.append(doctor.substring(4,5).toUpperCase());
sb.append(doctor.substring(5));
}
return sb.toString();
}
Guava
With Guava, you can write something like this:
import com.google.common.base.*;
import com.google.common.collect.*;
//...
String doctors = "doc_vijayan,doc_zubair,doc_Raja";
Function<String,String> chopAndCap =
new Function<String,String>() {
#Override public String apply(String from) {
return from.substring(4, 5).toUpperCase()
+ from.substring(5);
}
};
Iterable<String> docs = Splitter.on(',').split(doctors);
docs = Iterables.transform(docs, chopAndCap);
doctors = Joiner.on(", ").join(docs);
System.out.println(doctors);
// Vijayan, Zubair, Raja
So the concrete logical steps are:
Define a Function to perform the chop-and-cap
Use Splitter to split into Iterable<String>
Iterables.transform each element using the above Function
Use Joiner to join from the transformed Iterable back to a String
If you're comfortable with this kind of programming style, you can just assemble the entire process into one smooth operation:
System.out.println(
Joiner.on(", ").join(
Iterables.transform(
Splitter.on(',').split(doctors),
new Function<String,String>() {
#Override public String apply(String from) {
return from.substring(4, 5).toUpperCase()
+ from.substring(5);
}
}
)
)
);
// Vijayan, Zubair, Raja
Apache Commons Lang
With Apache Commons Lang, you can write something like this:
import org.apache.commons.lang.*;
//...
String doctors = "doc_vijayan,doc_zubair,doc_Raja";
String[] docs = StringUtils.split(doctors, ',');
for (int i = 0; i < docs.length; i++) {
docs[i] = StringUtils.capitalize(
StringUtils.substringAfter(docs[i], "doc_")
);
}
doctors = StringUtils.join(docs, ", ");
System.out.println(doctors);
// Vijayan, Zubair, Raja
Note that you if you have both Guava and Apache Commons Lang, you can use StringUtils.capitalize/substringAfter in chopAndCap function above.
final String[] docs = doctors.split(",");
final StringBuilder sb = new StringBuilder();
for (final String d : docs) {
String doct = d.replace("doc_", "");
doct = doct.subString(0,1).toUpperCase() + doct.subString(1).toLowerCase();
sb.append(sb.length() > 0 ? ", " : "");
sb.append(doct);
} // you should be able to do the rest.
String regex = "doc_.";
Matcher matcher = Pattern.compile(regex).matcher(doctors);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String group = matcher.group();
int i = group.length() - 1;
matcher.appendReplacement(sb, String.valueOf(group.charAt(i)).toUpperCase());
}
matcher.appendTail(sb);
System.out.print(sb.toString());
The easiest way is to use 'any' StringUtils library out there. For example org.apache.commons.lang.StringUtils has a chomp and a capitalize method which should bring you a long way.

Categories

Resources