Java: simpler way of cutting off end of string - java

Everytime I encounter this I ask myself the same question: Isn't there a simpler and less annoying way of cutting a string from the end by X characters.
Let's say I got "Helly there bla bla" and - why ever - I need to cut off the last 2 characters, resulting in "Helly there bla b".
I now would do the following:
String result = text.substring(0, text.length() - 2);
I rather want to do something like:
String result = text.cutOffEnd(2);
I know there are many String libraries out there, but don't know many of them and I never saw something like that so I hoped someone of you might know better :)
EDIT:
Q: Why don't you just build your own util method / class?
A: I don't want to use an own util method. I don't write a util method for "null or empty" or other trivial things. I go with the opinion that there MUST BE something available already as I would say that tons of people need this kind of function pretty often in their lifetime.
Plus: I work in many different projects and just want to rely on a simple library call like "Strings.nullToEmpty(str)" etc. I just don't build something like that on my own, although it's trivial.
Q: why is text.substring(0, text.length() - 2); not good enough?
A: It's very bulky if you compare it with my desired function. Also, think of that: If you determine the string, it becomes even unhandier:
String result = otherClass.getComplicatedCalculatedText(par1, par2).substring(0,
otherClass.getComplicatedCalculatedText(par1, par2).length() - 2);
Obviously I'd need to use a local variable, which is so unnecessary at this point... As it could simply be:
String result = otherClass.getComplicatedCalculatedText(par1, par2).cutOffEnd(2);

By using some string library. I suggest Apache's commons lang.
For your case this is enough.
import org.apache.commons.lang.StringUtils;
String result = StringUtils.removeEnd( "Helly there bla bla", "la");

Go through the following code
public class OddNumberLoop {
public static void main(String[] args) {
String st1 = "Helly there bla bla";
String st2 = st1.substring(0, st1.length() - 2);
System.out.println(st2);
}
}
Good Luck !!!

There is no built-in utility for this in the starnard library, but how hard is it to write a util method for this yourself?
public static String cutOffEnd(String s, int n) {
return s == null || s.length() <= n ? "" : s.substring(0, s.length() - n);
}
A complete solution with checks included:
public static String cutOffEnd(String s, int n) {
if (s == null)
throw new NullPointerException("s cannot be null!");
if (n > s.length())
throw new IllegalArgumentException("n cannot be greater"
+ " than the length of string!");
return s.substring(0, s.length() - n);
}

By the way: Often such feature-requests are made to the java-compiler. Usually these features are not Compelling for the Language and won't be fixed.
Why do you like to cut it off? If its for a higher-level-solution then you like to match a pattern or structure. In this case you anyway shall use a own Util-Method for parsing.
A realistic Example:
String url = "http://www.foo.bar/#abc";
String site = url.substring(0, url.indexOf("#"));
// this shall be extracted into a utils-method
// anyway like `MyURLParser.cutOfAnchor()`.
Its forbidden to ask for a concrete Library here.

Related

Spell-Check: Find one-to-one token difference mapping between two strings

I recently stumbled over this question on an internet archive and am having some difficulty wrapping my head around it. I want to find a desired mapping amongst the different tokens between two strings. The output should a String-to-String map.
For example:
String1: hewlottpackardenterprise helped american raleways in N Y
String2: hewlett packard enterprise helped american railways in NY
Output:
hewlottpackardenterprise -> hewlett packard enterprise
hewlott -> hewlett
raleways -> railways
N Y -> NY
Note: I have been able to write an edit-distance method, which finds all types of edits (segregated by types, like deletion, substitution etc.) and can convert the first string to second by a convert method
What have I tried so far?
Approach 1: I began with a naive approach of splitting both the strings by space, inserting the tokens of the first string into a hash map and comparing the tokens of the other string with this hashmap. However, this approach quickly fails as misses on relevant mappings.
Approach 2: I utilize my covert method to find the edit positions in the string, and type of edits. Using space edits, I'm able to create a mapping from hewlottpackardenterprise -> hewlett packardenterprise. However, the method just explodes as more and more things need to be splitted within the same word.
Appreciate any thoughts in this regard! Will clear any doubts in the comments.
public String returnWhiteSpaceEdittoken(EditDone e, List<String> testTokens) {
int pos = e.pos, count=0, i=0;
String resultToken = null;
if (e.type.equals(DeleteEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count==pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
resultToken = testTokens.get(i) + " " + testTokens.get(i+1);
} else if (e.type.equals(InsertEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count>pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
String token = testTokens.get(i);
resultToken = token.substring(count-token.length(), pos) + token.substring(pos, count);
}
return resultToken;
}
A pretty common way of handling problems like this is to find the longest common subsequence (or it's dual the shortest edit script) between the two strings and then post-process the output to get the specific format you want; in your case the string maps.
Wikipedia has a pretty decent introduction to the problem here: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
and a great paper "An O(ND) Difference Algorithm and Its Variations" by Myers can be found here. http://www.xmailserver.org/diff2.pdf

Calling substring Method?

I am fairly new to Java. Over the past few weeks I have been trying to teach myself java. This has been primarily based on tutorials i find online and forums I can find. So keep this in mind and any additional critique you can share is greatly appreciated! I am currently trying to create a calculator that runs off of if-else loops. I'm working on a method that allows the user to derive a function based on the principle that if
f(x)=ax^n+bx^o+cx^p... then f'(x)=anx^n-1+box^o-1+cpx^p-1...
I'm trying to use .split() to separate the parts of the function, perform the changes to the individual parts, and then print them together. I could get most of the way through this but I couldn't convert a string with a negative sign to an integer so I am trying to call a method that uses .substring and then replaceAll to get rid of the negative sign then convert to integer. However, I keep getting a compiling error stating the "actual and formal argument lists differ in length". Can anyone explain why this might be happening?
import java.util.Scanner;
import java.util.Arrays;
import java.lang.String;
public class InputInteger
{
public String changeSign(String second) {
String negative = second.substring(0,1);
return negative;
}
public static void splitFunction() {
Scanner o = new Scanner(System.in);
String function = o.next();
String[] parts = function.split("(?=\\+|\\-)");
for (int i = 0; i < parts.length;) {
String[] second = parts[i].split("(?=[0-9]+|[a-z]+|[A-Z]+\\^)");
InputInteger.changeSign();
if (negative = ("-")) {
second = second.replace("-","");
int x = Integer.parseInt(second[0]);
int y = Integer.parseInt(second[2]);
int w = x*y;
int z = y-1;
System.out.println(w + "x^" + z);
i++;
}
}
}
Problem that you are talking about is the method not working . You have to pass argument in the function like
InputInteger.changeSign(function);
or
InputInteger.changeSign(second[i]);
according to requirement
changeSign(String second) should be defined as static
negative variable is not defined
you should compare strings with equals() method
you call .replace(...) on an array, which doesn't have this method
And these are only compile errors, I see at least one runtime problem:
you increase i only in the if which may result in an infinite
loop...
I suggest you use some good IDE like Eclipse or IntelliJ IDEA, which will help you with warnings/errors/etc.
First of all in your code if (negative = ("-")) you have a single "=" and I think you meant to use "==" for comparison. Second, method parseInt() as well as valueOf() (which I prefer to parseInt()) should handle negative numbers just fine. there is no need to remove "-". Yout method changeSign() takes a String argument, also your method ChangeSign() returns String value and you must assign a result to some String: String negative = InputInteger.changeSign(str);. Plus also String class has a method startsWith(String prefix) that fits your better then substring(). Hope this helps. If anything there is an Open source library that provides a Utility for parsing String into Integer (among other things). in That util there is a method
parseStringToInt(String numStr, int defaultValue,
String nullOrEmptyStringErrorMessage, String numberFormatErrorMessage)
That tries to parse a String to Integer and if it does not succeed it returns a default value and never throws an Exception. That method definitely works fine with negative integers. Here is the link to the article about the library.https://www.linkedin.com/pulse/open-source-java-library-some-useful-utilities-michael-gantman?trk=pulse_spock-articles. There you will find the instructions on where to get the library including javadoc and source code.

String Fragment Combinations Puzzle

Let's say I am given a list of String fragments. Two fragments can be concatenated on their overlapping substrings.
e.g.
"sad" and "den" = "saden"
"fat" and "cat" = cannot be combined.
Sample input:
aw was poq qo
Sample output:
awas poqo
So, what's the best way to write a method which find the longest string that can be made by combining the strings in a list. If the string is infinite the output should be "infinite".
public class StringUtil {
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (int i = 0; i < fragments.size(); i++) {
char last = (char) (fragments.get(i).length() - 1);
if (Character.toString(last).equals(fragments.get(i).substring(0))) {
combined.append(fragments.get(i)).append(fragments.get(i+1));
}
}
return combined.toString();
}
}
Here's my JUnit test:
public class StringUtilTest {
#Test
public void combine() {
List<String> fragments = new ArrayList<String>();
fragments.add("aw");
fragments.add("was");
fragments.add("poq");
fragments.add("qo");
String result = StringUtil.combine(fragments);
assertEquals("awas poqo", result);
}
}
This code doesn't seem to be working on my end... It returning an empty string:
org.junit.ComparisonFailure: expected:<[awas poqo]> but was:<[]>
How can I get this to work? And also how can I get it to check for infinite strings?
I don't understand how fragments.get(i).length() - 1 is supposed to be a char. You clearly casted it on purpose, but I can't for the life of me tell what that purpose is. A string of length < 63 will be converted to an ASCII (Unicode?) character that isn't a letter.
I'm thinking you meant to compare the last character in one fragment to the first character in another, but I don't think that's what that code is doing.
My helpful answer is to undo some of the method chaining (function().otherFunction()), store the results in temporary variables, and step through it with a debugger. Break the problem down into small steps that you understand and verify the code is doing what you think it SHOULD be doing at each step. Once it works, then go back to chaining.
Edit: ok I'm bored and I like teaching. This smells like homework so I won't give you any code.
1) method chaining is just convenience. You could (and should) do:
String tempString = fragments.get(i);
int lengthOfString = tempString.length() - 1;
char lastChar = (char) lengthOfString;//WRONG
Etc.
This lets you SEE the intermediate steps, and THINK about what you are doing. You are literally taking the length of a string, say 3, and converting that Integer to a Char. You really want the last character in the string. When you don't use method chaining, you are forced to declare a Type of intermediate variable, which of course forces you to think about what the method ACTUALLY RETURNS. And this is why I told you to forgo method chaining until you are familiar with the functions.
2) I'm guessing at the point you wrote the function, the compiler complained that it couldn't implicitly cast to char from int. You then explicitly cast to a char to get it to shut up and compile. And now you are trying to figure out why it's failing at run time. The lesson is to listen to the compiler while you are learning. If it's complaining, you're messing something up.
3) I knew there was something else. Debugging. If you want to code, you'll need to learn how to do this. Most IDE's will give you an option to set a break point. Learn how to use this feature and "step through" your code line by line. THINK about exactly what step you are doing. Write down the algorithm for a short two letter pair, and execute it by hand on paper, one step at a time. Then look at what the code DOES, step by step, until you see somewhere it does something that you don't think is right. Finally, fix the section that isn't giving you the desired result.
Looking at your unit test, the answer seems to be quite simple.
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
combined.append(fragment.substring(1));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But seeing at your inqusition example, you might be looking for something like this,
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
int i = 1;
while (i < fragment.length() && i < combined.length() && combined.charAt(combined.length() - i - 1) == fragment.charAt(i))
i++;
combined.append(fragment.substring(i));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But note that for your test, it will generate aws poq which seems to be logical.

way to overcome MissingFormatArgumentException for String.format when there aren't enough arguments?

On Java, I know that the next thing is ok:
String test="aaa";
System.out.println(String.format(test,"asd"));
(prints "aaa")
However, I want to be able to handle the opposite thing, such as:
String test="aaa%sbbb";
System.out.println(String.format(test));
(this produces an exception java.util.MissingFormatArgumentException )
I wish to make it as general as possible, no matter how many specifiers/parameters are there, if there aren't enough values, just ignore them (skip all of the specifiers from the problematic position) and write the rest of the string (in the case I've shown, for example, it will write "aaabbb" ) .
Is it possible out of the box, or should I write a function that does it?
ok, i think i've got a working solution, and i also think it supports everything that String.format supports:
public static String formatString(final String stringToFormat,final Object... args)
{
if(stringToFormat==null||stringToFormat.length()==0)
return stringToFormat;
int specifiersCount=0;
final int argsCount=args==null ? 0 : args.length;
final StringBuilder sb=new StringBuilder(stringToFormat.length());
for(int i=0;i<stringToFormat.length();++i)
{
char c=stringToFormat.charAt(i);
if(c!='%')
sb.append(c);
else
{
final char nextChar=stringToFormat.charAt(i+1);
if(nextChar=='%'||nextChar=='n')
{
++i;
sb.append(c);
sb.append(nextChar);
continue;
}
// found a specifier
++specifiersCount;
if(specifiersCount<=argsCount)
sb.append(c);
else while(true)
{
++i;
c=stringToFormat.charAt(i);
// find the end of the converter, to ignore it all
if(c=='t'||c=='T')
{
// time prefix and then a character, so skip it
++i;
break;
}
if(c>='a'&&c<='z'||c>='A'&&c<='Z')
break;
}
}
}
return String.format(sb.toString(),args);
}
and a test, just to show it works:
System.out.println(formatString("aaa%sbbb"));
System.out.println(formatString("%da%sb%fc%tBd%-15se%16sf%10.2fg"));
sadly, it creates a new stringBuilder and a string on the way, but it works.
Is it possible out of the box, or should I write a function that does it?
It is not possible out of the box. There is nothing in the standard implementation for ignoring this.
I guess you could write a function that processes the format string to get rid of "unwanted" format specifiers. But it would most likely be easier to either:
choose or generate the format string based on the number of arguments you have,
call the format method once for each argument, or
do the formatting some other way entirely.

The method replaceVariables(String) is undefined for the type

I get this message for as many times as I have used replaceVariables in my code. I have added the referenced libraries, but I don't know what else to do. Can someone please help me?
Update: This is the code:
int k = 0;
for(Xml reg_is:fetchsite.child("site").child("regexps").children("reg"))
{
if(reg_is.string("name").contains("unique")){
if(reg_is.child("start").content()=="")
error += "\tNo prefix reg.exp. given.\n";
else
prefix = HtmlMethods.removeBreaks(replaceVariables(reg_is.child("start").content()));
if(reg_is.child("end").content()=="")
error += "\tNo suffix reg.exp. given.\n";
else
suffix = HtmlMethods.removeBreaks(replaceVariables(reg_is.child("end").content()));
}
else{
poleis[k][0]= HtmlMethods.removeBreaks(reg_is.string("name"));
poleis[k][1] = HtmlMethods.removeBreaks(replaceVariables(reg_is.child("start").content()));//ιδια δομη για ολες τις πολεις
poleis[k][2] = HtmlMethods.removeBreaks(replaceVariables(reg_is.child("end").content()));
k++;
}
}
In this part I use my XML in order to find the data from a HTML page that I want.
So, replaceVariables needs to be either a method which is declared in the same class, or it needs to be a static method which is imported using import static. Since it seems to be a method of the HtmlMethods class, my bet is that adding the following line to the imports should fix the problem:
import static com.example.HtmlMethods.*;
You only need to substitute com.example with the actual package name. Another way is to use HtmlMethods.replaceVariables(x) in your code instead.
That said, doing a string == "" is not the way to determine if the string equals an empty string. You should use either
if (string.equals("")) {}
or
if (string.length() == 0) {}
or
if (string.isEmpty()) {}
instead. Be aware that string is supposed to be non-null here, else you need to add a string != null as well or to use "".equals(string).
On == on reference types
someString == "" is almost always wrong. == is a reference identity comparison. If you want value comparison, use equals. In this particular case, you can use either someString.length() == 0 or someString.isEmpty()
Related questions
Java String.equals versus ==
On += on String
Be aware that this performs quite horribly (quadratic) with really long strings. If you're doing this in a any sizable loop, you'd definitely see the effect. It'd be better to use a StringBuilder.
Related questions
String vs StringBuilder
Why to use StringBuffer in Java instead of the string concatenation operator
StringBuilder and StringBuffer in Java

Categories

Resources