Context:
I wish to have a fixed string lenght since I'm formatting an output file, I built 2 functions that should be applied to string based on my string length.
First function: if you want a string X char long, but you got one which is X-Y, this adds spaces 'till desired length is reached, in this particular case, Y. This seems correct, it works
public String formatSpace(String s, int desiredlength){
while (s.length()<desiredlength){
s+=" ";
}
return s;
}
Second function: if you want a string X char long but you got one which is X+Y, this "removes" char until desired length is reached, in this particular case, Y. This seems to be wrong.
public String truncString(String s, int desiredlength){
return s.substr(0,s.length()-desiredlenght);
}
Error:
I apply these two based on string length that I test in another part of code:
[...]//here i built my class
int maxlen = 60;
[...] //here there is more code but it just collects data and I already tested fields
if (field.length()<maxlen){
field = formatSpace(field,maxlen);
}else if (field.length()>maxlen){
field = truncString(field,maxlen);
}
[...] //here i put string on file
Error I get is about string index being negative, I don't know why, I tried code on paper (yes, I know it's dumb) but it works there
Why second function is not working?
Also, it would be better to make one function which format my string, how should I make it?
Solution:
Thanks to everyone who commented, I solved my problem with this single function I wrote, I don't even test string anymore, if they fit my length they're ok, else I format them:
private String formatString(String s, int length) {
while (s.length() < length) {
s += " ";
}
return s.substring(0, length);
}
Second argument in substring function is the length of your new String. Why do you have a substraction ?
This should work :
public String truncString(String s, int desiredlength){
return s.substr(0,desiredlenght);
}
I usually use something like:
private static String spaces(int width) {
// May be more efficient ways of doing this.
return String.join("", Collections.nCopies(width, " "));
}
private static String fixedWidth(String s, int width, boolean padLeft) {
String spaces = spaces(Math.max(0,width-s.length()));
return (padLeft ? spaces + s : s + spaces).substring(0, width);
}
public void test(String[] args) {
String[] tests = {"Hello", "Loooooooooooooong!!!"};
for ( String t: tests) {
System.out.println(fixedWidth(t,10,false));
System.out.println(fixedWidth(t,10,true));
}
}
Or you can try this approach for a simple one line solution.
String test="type something here";
int desiredLength=15;
System.out.println(String.format("%1$-"+desiredLength+"s", test.substring(0, desiredLength)));
The idea is => substring first to the desired length (this will happen if string is longer) and then use String format to fill to desired length with spaces ( %1$-10s is the format for left aligned string filled to 10 spaces).
You have a typo. Inside truncString you write desiredlenght instead of desiredlength.
The problem in the second function is a logic problem. Imagine you're desired length is 4 and you introduce a String which length is 6. If you do the String length - desired length you're going to obtain a String which length is 2.
A way to fix this problem is to return directly the substr: return s.substr(0,desiredLenght)
Related
I want to find out if a string that is comma separated contains only the same values:
test,asd,123,test
test,test,test
Here the 2nd string contains only the word "test". I'd like to identify these strings.
As I want to iterate over 100GB, performance matters a lot.
Which might be the fastest way of determining a boolean result if the string contains only one value repeatedly?
public static boolean stringHasOneValue(String string) {
String value = null;
for (split : string.split(",")) {
if (value == null) {
value = split;
} else {
if (!value.equals(split)) return false;
}
}
return true;
}
No need to split the string at all, in fact no need for any string manipulation.
Find the first word (indexOf comma).
Check the remaining string length is an exact multiple of that word+the separating comma. (i.e. length-1 % (foundLength+1)==0)
Loop through the remainder of the string checking the found word against each portion of the string. Just keep two indexes into the same string and move them both through it. Make sure you check the commas too (i.e. bob,bob,bob matches bob,bobabob does not).
As assylias pointed out there is no need to reset the pointers, just let them run through the String and compare the 1st with 2nd, 2nd with 3rd, etc.
Example loop, you will need to tweak the exact position of startPos to point to the first character after the first comma:
for (int i=startPos;i<str.length();i++) {
if (str.charAt(i) != str.charAt(i-startPos)) {
return false;
}
}
return true;
You won't be able to do it much faster than this given the format the incoming data is arriving in but you can do it with a single linear scan. The length check will eliminate a lot of mismatched cases immediately so is a simple optimization.
Calling split might be expensive - especially if it is 200 GB data.
Consider something like below (NOT tested and might require a bit of tweaking the index values, but I think you will get the idea) -
public static boolean stringHasOneValue(String string) {
String seperator = ",";
int firstSeparator = string.indexOf(seperator); //index of the first separator i.e. the comma
String firstValue = string.substring(0, firstSeparator); // first value of the comma separated string
int lengthOfIncrement = firstValue.length() + 1; // the string plus one to accommodate for the comma
for (int i = 0 ; i < string.length(); i += lengthOfIncrement) {
String currentValue = string.substring(i, firstValue.length());
if (!firstValue.equals(currentValue)) {
return false;
}
}
return true;
}
Complexity O(n) - assuming Java implementations of substring is efficient. If not - you can write your own substring method that takes the required no of characters from the String.
for a crack just a line code:
(#Tim answer is more efficient)
System.out.println((new HashSet<String>(Arrays.asList("test,test,test".split(","))).size()==1));
I need to write a program where the main reads two strings as input: if the strings have the same length, then it has to pass the whole first string and the first char of the second string to a method called find, which has to return 'true' if the character appears even a single time on the string. If the length differs, then it will pass the whole second sentence and the last char of the first string to find. At last, the main will give whatever the method returns as output, so it has to be true, or false. I've created the whole main, and it works correctly, but I have no idea how to create the find method. Here is the code:
import java.util.Scanner;
public class Exercise {
/*
* public static boolean find(String... sentence, char... character) {
* // No, I can't use multiple varargs...
* }
*/
public static void main(String[] args) {
String first, second;
char firstChar, lastChar;
Scanner keyboard = new Scanner(System.in);
int lengthFirst, lengthSecond;
boolean goal = true;
first = keyboard.nextLine();
lengthFirst = first.length();
lastChar = first.charAt(lengthFirst - 1);
second = keyboard.nextLine();
lengthSecond = second.length();
firstChar = second.charAt(0);
System.out.println("Length 1: " + lengthFirst); // Those lines are test lines.
System.out.println("Length 2: " + lengthSecond); // They're here just to check
System.out.println("Char 1: " + firstChar); // if everything else works.
System.out.println("Char 2: " + lastChar);
if (lengthFirst == lengthSecond) {
goal = find(first, firstChar);
System.out.println("Goal is: " + goal);
System.exit(0);
} else
goal = find(second, lastChar);
System.out.println("Goal is: " + goal);
System.exit(0);
}
}
I was thinking about using the varargs option, using a varargs for the String, and another for the char, and then using a 'for' loop inside of the method to check if the character appears or not, and everything was easy on my head...but with some research I found out it will be a waste of time, because I can't use two varargs on the same method. The for loop idea works, but I can't figure out how to pass only the right String and the right Char. How should I pass them to the method, without passing them both?
Edit: No, this is not a duplicate. I allow loops, the other question doesn't. Also, my problem is about how am I supposed to pass multiple variables, but then using just some. That's an example:
The strings are both long 50, so the method needs to use only 'first' as String, and 'firstChar' as Char.
You can use String.indexOf().
returns the index within this string of the first occurrence of the
specified character. If a character with value ch occurs in the
character sequence represented by this String object, then the index
(in Unicode code units) of the first such occurrence is returned, if
no such character occurs in this string, then -1 is returned.
public static boolean find(String str, char ch){
if(str.indexOf(ch) == -1)
return false;
return true;
}
As you are thinking, you don't need four parameters for this function. You can use this function with two parameters for both cases:
goal = find(first, firstChar);
goal = find(second, lastChar);
EDIT I think you have misunderstood the way the parameters are mapped.
if you have a function like
public static boolean find(String str, char ch){
//do something
}
You don't need to call the find with same parameters str and ch, I mean find(str,ch). You can call them with any parameter, with any name, like :
goal = find(s,c); // s is a string and c is a char
goal = find(a,b); // a is a string and b is a char
when you call find(s,c), s will be mapped to the first argument in your function that is str and c will be mapped to your second argument that is ch.
This is the reason you are able to call both find(first, firstChar) and find(second, lastChar) with a single function.
private static boolean find(String str, char Char) {
for(int i=0;i<str.length();i++)
if(str.charAt(i)==Char)
return true;
return false;
}
This would help hopefully...
Seems like what you are looking for is:
if (second.indexOf(c) == -1) return false; //char c not found
return true;
Find will simply contain
private boolean find(String subject, char first) {
return subject.indexOf(first) > -1;
}
I want my code whenever I input a base from 2-36 , It can output a number which is decimal. here is my code
package code;
public class solution{
public static int x2ten(String s, int base){
String[] bits = s.split("");
int result = 0;
for(int i=0; i < bits.length; i++ ){
int val = (Integer.parseInt(bits[bits.length-1-i])) * ((int)Math.pow(base,i));
val = charToInt(Integer.parseInt(bits[bits.length-1-i]))* ((int)Math.pow(base,i));
result += val;
}
return result;
}
public static int charToInt(char c){
char[] characters = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G',
'H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
for(int j = 0; j<characters.length; j++){
if(characters[j] == c){
return j;
}
}
return -1;
}
public static void main(String[] args)
{
System.out.println(x2ten("1101",2));
}
}
There is a problem at first appear charToInt, it said that I should change charToInt(char c) to charToInt(int c). But whats purpose of charToInt is convert whatever I input a Character like 1A, then it can output 26 in decimal.
This is a wheel that's already been invented:
public static int x2ten(String s, int base) {
return Integer.parseInt(s, base);
}
I would advise deleting your method entirely in favour of the one from the JDK, which even has the same signature.
If you insist on using your own code, you should maybe take in mind following things:
If you want to get an array for all characters in a string, use the toCharArray() method. This gives you a char[], which will also be more useful in the rest of your program
What's the point of assigning a value to val if you never use that value and immediately get another value in there. Get rid of that first line. It doesn't seem to be very useful, does it?
Be careful with Integer.parseInt(String s) if you use literals in your numbers. It should throw a NumberFormatException.
If you can notice that in the function call to the function charToInt(), you are passing an integer as an argument but if you see the definition of your function, it is expecting a character.Hence it is suggesting you to change it to int. Hope this helps :)
I'm using codingbat.com to get some java practice in. One of the String problems, 'withoutString' is as follows:
Given two strings, base and remove, return a version of the base string where all instances of the remove string have been removed (not case sensitive).
You may assume that the remove string is length 1 or more. Remove only non-overlapping instances, so with "xxx" removing "xx" leaves "x".
This problem can be found at: http://codingbat.com/prob/p192570
As you can see from the the dropbox-linked screenshot below, all of the runs pass except for three and a final one called "other tests." The thing is, even though they are marked as incorrect, my output matches exactly the expected output for the correct answer.
Here's a screenshot of my output:
And here's the code I'm using:
public String withoutString(String base, String remove) {
String result = "";
int i = 0;
for(; i < base.length()-remove.length();){
if(!(base.substring(i,i+remove.length()).equalsIgnoreCase(remove))){
result = result + base.substring(i,i+1);
i++;
}
else{
i = i + remove.length();
}
if(result.startsWith(" ")) result = result.substring(1);
if(result.endsWith(" ") && base.substring(i,i+1).equals(" ")) result = result.substring(0,result.length()-1);
}
if(base.length()-i <= remove.length() && !(base.substring(i).equalsIgnoreCase(remove))){
result = result + base.substring(i);
}
return result;
}
Your solution IS failing AND there is a display bug in coding bat.
The correct output should be:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours is:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours fails because it is removing spaces, but also, coding bat does not display the correct expected and run output string due to HTML removing extra spaces.
This recursive solution passes all tests:
public String withoutString(String base, String remove) {
int remIdx = base.toLowerCase().indexOf(remove.toLowerCase());
if (remIdx == -1)
return base;
return base.substring(0, remIdx ) +
withoutString(base.substring(remIdx + remove.length()) , remove);
}
Here is an example of an optimal iterative solution. It has more code than the recursive solution but is faster since far fewer function calls are made.
public String withoutString(String base, String remove) {
int remIdx = 0;
int remLen = remove.length();
remove = remove.toLowerCase();
while (true) {
remIdx = base.toLowerCase().indexOf(remove);
if (remIdx == -1)
break;
base = base.substring(0, remIdx) + base.substring(remIdx + remLen);
}
return base;
}
I just ran your code in an IDE. It compiles correctly and matches all tests shown on codingbat. There must be some bug with codingbat's test cases.
If you are curious, this problem can be solved with a single line of code:
public String withoutString(String base, String remove) {
return base.replaceAll("(?i)" + remove, ""); //String#replaceAll(String, String) with case insensitive regex.
}
Regex explaination:
The first argument taken by String#replaceAll(String, String) is what is known as a Regular Expression or "regex" for short.
Regex is a powerful tool to perform pattern matching within Strings. In this case, the regular expression being used is (assuming that remove is equal to IS):
(?i)IS
This particular expression has two parts: (?i) and IS.
IS matches the string "IS" exactly, nothing more, nothing less.
(?i) is simply a flag to tell the regex engine to ignore case.
With (?i)IS, all of: IS, Is, iS and is will be matched.
As an addition, this is (almost) equivalent to the regular expressions: (IS|Is|iS|is), (I|i)(S|s) and [Ii][Ss].
EDIT
Turns out that your output is not correct and is failing as expected. See: dansalmo's answer.
public String withoutString(String base, String remove) {
String temp = base.replaceAll(remove, "");
String temp2 = temp.replaceAll(remove.toLowerCase(), "");
return temp2.replaceAll(remove.toUpperCase(), "");
}
Please find below my solution
public String withoutString(String base, String remove) {
final int rLen=remove.length();
final int bLen=base.length();
String op="";
for(int i = 0; i < bLen;)
{
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
i +=rLen;
continue;
}
op += base.substring(i, i + 1);
i++;
}
return op;
}
Something things go really weird on codingBat this is just one of them.
I am adding to a previous solution, but using a StringBuilder for better practice. Most credit goes to Anirudh.
public String withoutString(String base, String remove) {
//create a constant integer the size of remove.length();
final int rLen=remove.length();
//create a constant integer the size of base.length();
final int bLen=base.length();
//Create an empty string;
StringBuilder op = new StringBuilder();
//Create the for loop.
for(int i = 0; i < bLen;)
{
//if the remove string lenght we are looking for is not less than the base length
// and the base substring equals the remove string.
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
//Increment by the remove length, and skip adding it to the string.
i +=rLen;
continue;
}
//else, we add the character at i to the string builder.
op.append(base.charAt(i));
//and increment by one.
i++;
}
//We return the string.
return op.toString();
}
Taylor's solution is the most efficient one, however I have another solution that is a naive one and it works.
public String withoutString(String base, String remove) {
String returnString = base;
while(returnString.toLowerCase().indexOf(remove.toLowerCase())!=-1){
int start = returnString.toLowerCase().indexOf(remove.toLowerCase());
int end = remove.length();
returnString = returnString.substring(0, start) + returnString.substring(start+end);
}
return returnString;
}
#Daemon
your code works. Thanks for the regex explanation. Though dansalmo pointed out that codingbat is displaying the intended output incorrectly, I through in some extra lines to your code to unnecessarily account for the double spaces with the following:
public String withoutString(String base, String remove){
String result = base.replaceAll("(?i)" + remove, "");
for(int i = 0; i < result.length()-1;){
if(result.substring(i,i+2).equals(" ")){
result = result.replace(result.substring(i,i+2), " ");
}
else i++;
}
if(result.startsWith(" ")) result = result.substring(1);
return result;
}
public String withoutString(String base, String remove){
return base.replace(remove,"");
}
I've an array with hundreds of string values, Is it possible to use specific formats to make them shorter?
e.g
Normal -> "Hello John, What's up?!"
With short format -> "Hello John..."
After using substring, I got errors.
private String[] finalString;
for (int i = 0; i < arrays.PodcastTitle.length; i++) {
finalString[i] = arrays.PodcastTitle[i].substring(0, 5);
}
Since you haven't given any details, this is the shortest approach :
String little = normalString.substring(0, 10); // use anything 5 or 10 or 15, depending on how short you want to make your String
From your edit:
Please change:
private String[] finalString;
to:
private String[] finalString = new String[whateverSizeYouWant];
String toLitteString(String str, int length) {
if (str.length() > length) return str.substring(0, length) + "...";
return str;
}
Function that will truncate longer strings to length (and add a "...") or return the short string. If you want the length to include the "..." then just change length to length - 3.
Why won't you consider implementing a method that takes a String argument, explodes it by space character and returns the String with required number of words in it?