You have
user.nick#domain.com
and result should be:
******#domain.com
Currently I'm doing it this way:
public static String removeUserFromEmail(String email) {
StringBuffer sbEmail = new StringBuffer(email);
int start = sbEmail.indexOf("#");
sbEmail.delete(0, start);
return "******" + sbEmail.toString();
}
Is there something simpler or more elegant?
i would be inclined to run indexOf on email string before putting it in the stringbuffer...
int start = email.indexOf( '#' );
if( start == -1 )
{
// handle invalid e-mail
}
else
{
return "*****" + email.substring( start );
}
Nothing wrong with that solution, although I have two suggestions:
1) Use StringBuilder instead of StringBuffer unless you need to synchronize access between multiple threads. There is a performance penalty associated with StringBuffer that for this application is likely unnecessary.
2) One of the benefits of StringBuilder/Buffer is avoiding excessive string concatenations.
Your return line converts the Buffer to a string, and then concatenates. I would probably do this instead:
int start = email.indexOf("#");
if (start < 0) {
return ""; // pick your poison for the error condition
}
StringBuilder sbEmail = new StringBuilder(email);
sbEmail.replace(0, start, "******");
return sbEmail.toString();
FYI - my solution is really just some thoughts on your current use of StringBuffer (which are hopefully helpful). I would recommend Konstantin's solution for this simple string exercise. Simple, readable, and it gives you the opportunity to handle the error condition.
"some.user#domain.com".replaceAll("^[^#]+", "******");
Looks OK. Better check if indexOf returns -1.
public static String removeUserFromEmail(String email) {
String[] pieces = email.split("#");
return (pieces.length > 1 ? "******" + pieces[1] : email);
}
You could use a regex, but your solution seems fine to me. Probably faster than the regex too.
Related
So recently I got invited to this google foo.bar challenge and I believe the code runs the way it should be. To be precise what I need to find is the number of occurrences of "abc" in a String. When I verify my code with them, I pass 3/10 test cases. I'm starting to feel bad because I don't know what I am doing wrong. I have written the code which I will share with you guys. Also the string needs to be less than 200 characters. When I run this from their website, I pass 3 tests and fail 7. Basically 7 things need to be right.
The actual question:
Write a function called answer(s) that, given a non-empty string less
than 200 characters in length describing the sequence of M&Ms. returns the maximum number of equal parts that can be cut from the cake without leaving any leftovers.
Example : Input : (string) s = "abccbaabccba"
output : (int) 2
Input: (string) s = "abcabcabcabc"
output : (int) 4
public static int answer(String s) {
int counter = 0;
int index;
String findWord ="ABC";
if(s!=null && s.length()<200){
s = s.toUpperCase();
while (s.contains(findWord))
{
index = s.indexOf(findWord);
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
I see a couple of things in your code snippet:
1.
if(s.length()<200){
Why are you checking for the length to be lesser than 200? Is that a requirement? If not, you can skip checking the length.
2.
String findWord ="abc";
...
s.contains(findWord)
Can the test program be checking for upper case alphabets? Example: "ABC"? If so, you might need to consider changing your logic for the s.contains() line.
Update:
You should also consider putting a null check for the input string. This will ensure that the test cases will not fail for null inputs.
The logic of your code is well but on the other hand i found that you didn't check for if input string is empty or null.
I belief that google foo.bar wants to see the logic and the way of coding in a proper manner.
so don't be feel bad
I would go for a simpler approach
int beforeLen = s.length ();
String after = s.replace (findWord, "");
int afterLen = after.length ();
return (beforeLen - afterLen) / findWord.length ();
String pattern = "abc";
String line="<input text here>";
int i=0;
Pattern TokenPattern=Pattern.compile(pattern);
if(line!=null){
Matcher m=TokenPattern.matcher(line);
while(m.find()){
i++;
}}
System.out.println("No of occurences : "+ " "+i);
put declaration of index out before while block, isn't never good re-declare the same variable n time.
int index;
while (s.contains(findWord))
{
index = s.indexOf(findWord);
....
}
I hope this help
Update:
try to compact your code
public static int answer(String s) {
int counter = 0;
int index;
String findWord = "ABC";
if (s != null && s.length() < 200) {
s = s.toUpperCase();
while ((index = s.indexOf(findWord)) > -1) {
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
Update:
The logic seems good to me, I'm still try to improve the performance, if you can try this
while ((index = s.indexOf(findWord, index)) > -1) {
//s = s.substring(index + findWord.length(), s.length());
index+=findWord.length();
counter++;
}
I have:
String str = "Hello, how, are, you";
I want to create a helper method that removes the commas from any string. Which of the following is more accurate?
private static String removeComma(String str){
if(str.contains(",")){
str = str.replaceAll(",","");
}
return str;
}
OR
private static String removeComma(String str){
str = str.replaceAll(",","");
return str;
}
Seems like I don't need the IF statement but there might be a case where I do.
If there is a better way let me know.
Both are functionally equivalent but the former is more verbose and will probably be slower because it runs an extra operation.
Also note that you don't need replaceAll (which accepts a regular expression): replace will do.
So I would go for:
private static String removeComma(String str){
return str.replace(",", "");
}
The IF statement is unnecessary, unless you're handling "large" strings (we're talking megabytes or more).
If you're using the IF statement, your code will first search for the first occurance of a comma, and then execute the replacement. This could be costly if the comma is near the end of the string and your string is large, since it will have to be traversed twice.
Without the IF statement, commas will be replaced if they exist. If the answer is negative, your string will be untouched.
Bottom rule: use the version without the IF statement.
Both are correct, but the second one is cleaner since the IF statement of the first alternative is not needed.
It's a matter of what is the probability to have strings with comma in your universe of strings.
If you have a high probability, call the method replaceAll without checking first.
BUT If you are not using extremely huge strings, I guess you will see no difference in perfomance at all.
Just another solution with time complexity O(n), space complexity O(n):
public static String removeComma(String str){
int length = str.length();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
char c = str.charAt(i);
if (c != ',') {
sb.append(c);
}
}
return sb.toString();
}
The problem I am solving is replacing all Strings from another String.
I solved this problem fairly easily on codingbat.com by using String.replaceAll, and doing it until the first String no longer contains the other String.
However, I dislike this method as it is very slow. I have tried searching this website for more efficient methods, and came across these questions:
Fastest way to perform a lot of strings replace in Java
String.replaceAll is considerably slower than doing the job yourself
They solved the problem by using StringUtils and Patterns. I still think these methods are too slow!
When I code problems like these, I like to get my runtime under two seconds with Java. I'm testing this with a String of 1,000,000 characters. String.replaceAll went well over two seconds, and so did the other two methods.
Does anyone have a fast solution for this problem? Thanks!
EDIT: Unfortunately, the answers I received still run too slowly. And yes, I did mean make a new String, not change the old String, sorry for that mistake.
I'm not sure how it would work, but I think looping over each char and checking might work. Something with algorithms.
Strings are immutable so you can't remove stuff from them. Which means that you need to create a new String without the stuff that you want removed. When you use String.replace that is pretty much what it does: it creates a new String.
Beware of String.replaceAll since it uses a regular expression that gets compiled every time you call it (so never use it in a long loop). This is likely your problem.
If you need to use regular expressions, use the Pattern class to compile your regex and reuse the instance to create a new Matcher for each string you process. If you don't reuse your Pattern instance, it is going to be slow.
If you don't need a regular expression, StringUtils has a replaceEach() that does not rely on regular expressions.
If you are processing a large String. You may want to do things in a streaming fashion and loop over the characters and copy characters over to a StringBuilder.
Alternatively, you could use a regular expression to search for a particular pattern in the String and loop over the matches it finds and for each match append everything from the previous match to the current match to a StringBuilder.
The problem is your String in enormous, you only want to move/copy it once, and all the solutions that use multiple calls to replace will still end up doing an enormous amount of unnecessary work.
What you really want to use is Apache StringUtils.replaceEachRepeatedly, as that method handles searching for multiple strings while only building the result string one.
Apart of the time that each methods (replace, StringUtils or Patterns, ...) takes you only have one Thread working.
If you can split the work done by that thread in two or more, for example each Thread runs for a specific position in the string to other, you will be able to have a fast solution.
The tricky part is to divide the work and then join it together.
That will depend how you read the string, where do you write it in the end for example.
Regards,
I have faced the same problem some time ago and came to this post: Replace all occurrences of a String using StringBuilder?
Using the implementation given in the post:
public static void main(String[] args) {
String from = "A really long string full of ands and ors";
String replaceFrom = "and";
String replaceTo = "or";
long initTime = System.nanoTime();
String result1 = from.replace(replaceFrom, replaceTo);
System.out.println("Time1: " + (System.nanoTime() - initTime));
System.out.println(result1);
StringBuilder sb1 = new StringBuilder(from);
initTime = System.nanoTime();
replaceAll(sb1, replaceFrom, replaceTo);
System.out.println("Time1: " + (System.nanoTime() - initTime));
System.out.println(sb1.toString());
}
// From https://stackoverflow.com/questions/3472663/replace-all-occurences-of-a-string-using-stringbuilder
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 explanation of the better performance of the second solution is that it relays on StringBuilder, a mutable object rather than on String an immutable one. See Immutability of Strings in Java for a better explanation.
This solution will work both using StringBuffer and StringBuilder, but as explained in Difference between StringBuilder and StringBuffer StringBuffer is synchronized and StringBuilder is not, so if you don't need synchronisation you better use StringBuilder.
I just tried this, which resulted in :
100960923
197642683484
import java.util.Stack;
public class Test {
public static String removeAll(final String stringToModify, final String stringToFindAndRemove) {
if (stringToModify==null||stringToModify.length()==0) return new String(stringToModify);
if (stringToFindAndRemove==null||stringToFindAndRemove.length()==0) return new String(stringToModify);
if (stringToModify.length()<stringToFindAndRemove.length()) return new String(stringToModify);
int lastChar = 0;
int buffPos=0;
Stack<Integer>stack = new Stack<Integer>();
char[] chars = stringToModify.toCharArray();
char[] ref = stringToFindAndRemove.toCharArray();
char[] ret = new char[chars.length];
for (int a=0;a<chars.length;a++) {
if (chars[a]==ref[buffPos]) {
if (buffPos==ref.length-1) {
buffPos=0;
stack.pop();
} else {
if (buffPos==0) stack.push(lastChar);
buffPos++;
}
} else {
if (buffPos!=0) {
for (int b=0;b<buffPos;b++) {
ret[lastChar]=ref[b];
lastChar++;
}
a--;
buffPos = 0;
} else {
ret[lastChar]=chars[a];
lastChar++;
}
}
if (stack.size()>0&&(lastChar-stack.peek()>=ref.length)) {
while(stack.size()>0 && (lastChar-stack.peek()>=ref.length)) {
int top = stack.pop();
boolean f = true;
for (int foo=0;foo<ref.length;foo++) {
if (ret[top+foo]!=ref[foo]) {
f=false;
break;
}
}
if (f) lastChar=top;
}
}
}
if (buffPos!=0) {
for (int b=0;b<buffPos;b++) {
ret[lastChar]=ref[b];
lastChar++;
}
}
char[] out = new char[lastChar];
System.arraycopy(ret,0,out,0,lastChar);
return new String(out);
}
public static void main(final String[] args) {
StringBuffer s = new StringBuffer();
StringBuffer un = new StringBuffer();
for (int a=0;a<100000;a++) {
s.append("s");
un.append("un");
}
StringBuffer h = new StringBuffer(s);
h.append(un);
h.append("m");
String huge = h.toString();
String t = "sun";
long startTime = System.nanoTime();
String rep = removeAll(huge,t);
long endTime = System.nanoTime();
long duration = (endTime - startTime);
//System.out.println(rep);
System.out.println(duration);
startTime = System.nanoTime();
rep = new String(huge);
int pos = rep.indexOf(t);
while (pos!=-1) {
rep = rep.replaceAll(t,"");
pos = rep.indexOf(t);
}
endTime = System.nanoTime();
duration = (endTime - startTime);
//System.out.println(rep);
System.out.println(duration);
}
}
I'd be interested to see how fast this runs on someone elses machine. Because my boss thinks my machine is fast enough! :)
I have created an application to process log files but am having some bottle neck when the amount of files = ~20
The issue comes from a particular method which takes on average a second or so to complete roughly and as you can imagime this isn't practical when it needs to be done > 50 times
private String getIdFromLine(String line){
String[] values = line.split("\t");
String newLine = substringBetween(values[4], "Some String : ", "Value=");
String[] split = newLine.split(" ");
return split[1].substring(4, split[1].length());
}
private String substringBetween(String str, String open, String close) {
if (str == null || open == null || close == null) {
return null;
}
int start = str.indexOf(open);
if (start != -1) {
int end = str.indexOf(close, start + open.length());
if (end != -1) {
return str.substring(start + open.length(), end);
}
}
return null;
}
A line comes from the reading of a file which is very efficient so I don't feel a need to post that code unless someone asks.
Is there anyway to improve perofmrance of this at all?
Thanks for your time
A few things are likely problematic:
Whether or not you realized, you are using regular expressions. The argument to String.split() is a treated as a regex. Using String.indexOf() will almost certainly be a faster way to find the particular portion of the String that you want. As HRgiger points out, Guava's splitter is a good choice because it does just that.
You're allocating a bunch of stuff you don't need. Depending on how long your lines are, you could be creating a ton of extra Strings and String[]s that you don't need (and the garbage collecting them). Another reason to avoid String.split().
I also recommend using String.startsWith() and String.endsWith() rather that all of this stuff that you're doing with the indexOf() if only for the fact that it'd be easier to read.
I would try to use regular expressions.
One of the main problems in this code is the "split" method.
For example this one:
private String getIdFromLine3(String line) {
int t_index = -1;
for (int i = 0; i < 3; i++) {
t_index = line.indexOf("\t", t_index+1);
if (t_index == -1) return null;
}
//String[] values = line.split("\t");
String newLine = substringBetween(line.substring(t_index + 1), "Some String : ", "Value=");
// String[] split = newLine.split(" ");
int p_index = newLine.indexOf(" ");
if (p_index == -1) return null;
int p_index2 = newLine.indexOf(" ", p_index+1);
if (p_index2 == -1) return null;
String split = newLine.substring(p_index+1, p_index2);
// return split[1].substring(4, split[1].length());
return split.substring(4, split.length());
}
UPD: It could be 3 times faster.
I would recommend to use the VisualVM to find the bottle neck before oprimisation.
If you need performance in your application, you will need profiling anyways.
As optimisation i would make an custom loop to replace yours substringBetween method and get rid of multiple indexOf calls
Google guava splitter pretty fast as well.
Could you try the regex anyway and post results please just for comparison:
Pattern p = Pattern.compile("(Some String : )(.*?)(Value=)"); //remove first and last group if not needed (adjust m.group(x) to match
#Test
public void test2(){
String str = "Long java line with Some String : and some object with Value=154345 ";
System.out.println(substringBetween(str));
}
private String substringBetween(String str) {
Matcher m = p.matcher(str);
if(m.find(2)){
return m.group(2);
}else{
return null;
}
}
If this is faster find a regex that combines both functions
In php, the method ucwords converts any string in a string where each words first character is in uppercase, and all other characters are lower case.
I always end up making my own implementation, and I'm wondering if a standard method exists.
That's called capitalization. Use Apache Commons's StringUtils to do that.
See more here:
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
WordUtils is also worth looking at. See here
Otherwise it's a rather simple fix such as; String string1 = someString.substring(0,1).toUpperCase() + someString.substring(1);
You can put it in a function, and call it whenever you need. Saves you the trouble of maintaining libraries you don't need. (not that apache commons is ever trouble, but you get the point..)
EDIT: someString.substring(1) part can be written as someString.substring(1).toLowerCase() just to make sure that the rest of the string is in lowercase
I don't know about any direct equivalent, but you can always write one:
public static String capitalize(String input) {
if (input == null || input.length() <= 0) {
return input;
}
char[] chars = new char[1];
input.getChars(0, 1, chars, 0);
if (Character.isUpperCase(chars[0])) {
return input;
} else {
StringBuilder buffer = new StringBuilder(input.length());
buffer.append(Character.toUpperCase(chars[0]));
buffer.append(input.toCharArray(), 1, input.length()-1);
return buffer.toString();
}
}