I need to parse an input string into a new class object consisting of two floats. I do have a solution but it looks cumbersome. I wondered if there is a more elegant way to do it, esp. if the string splits only to 2 substrings and a cycle seems to be a bit of overkill?
my class:
public class Float2 {
public float width;
public float height;
}
my method to parse the input string into a class object:
public Float2 parseStringToFloat2(String inputstring) {
String[] stringarray = inputstring.split(",");
float[] floats = new float[2];
for (int i = 0; i <2; ++i) {
float number = Float.parseFloat(stringarray[i]);
floats[i] = number;
}
return new Float2(floats[0], floats[1]);
}
I do think the loop is an overkill if you know for sure there will by only 2 parts.
Maybe try this:
public Float2 parseStringToFloat2(String inputstring){
String[] stringarray = inputstring.split(",");
try {
return new Float2(Float.parseFloat(stringarray[0]), Float.parseFloat(stringarray[1]));
} catch (Exception e) {
// catch logic
}
return null;
}
As said in a comment, you should also use try catch logic in case of a conversion error.
Another solution would be to use a Scanner. It is a more flexible solution if you need Locale-specific parsing (it uses the default locale without setting it, which could be problematic if a , is a decimal separator there). Also if you use a regex delim, the pattern can be precompiled to be faster.
public static Optional<Float2> parseStringToFloat2(String inputstring) {
final Scanner in = new Scanner(inputstring).useLocale(Locale.US).useDelimiter(", ");
// in.useDelimiter(Pattern.compile("\\s*,\\s*"));
try {
return Optional.of(new Float2(in.nextFloat(), in.nextFloat()));
} catch (NoSuchElementException e) {
return Optional.empty();
}
}
Related
I managed to make these two classess, but "score" has to have 7 digits after the dot. I cannot modify Main class. I think I should use String.format("%.7f", ...) but I don't know where. Please help.
MAIN:
public class Main {
public static void main(String[] args) {
Calc c = new Calc();
String score = c.doCalc(args[0]);
System.out.println(score);
}
}
CALC:
public class Calc {
public String doCalc(String cmd) {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
try {
return engine.eval(cmd).toString();
}
catch (ScriptException e) {
return "Invalid command to calc";
}
}
}
Instead of using system.out.println, you should use system.out.format or system.out.printf. See a short tutorial from Oracle on using it here. Why exactly can't you modify the main class? That seems to be where your score is being printed..
You can parse the string result back to Double and feed it to String.format:
try {
return String.format("%.7f", Double.valueOf(engine.eval(cmd).toString()));
}
catch (Exception e) {
return "Invalid command to calc";
}
You could of course feed the result directly to String.format without the toString and valueOf round trip, like so:
return String.format("%.7f", engine.eval(cmd));
But that only works when the eval result is a valid floating point number. To deal with other cases like integers or non-numbers, you'd have to put in a few type checks and make the code look more cluttered.
Here is the function i wrote. it take a Stringbuffer text then assign v[0]=text[0] , then starts from text[1] >>>text[n-1] the comparing. The vector v should contain the characters. I don't know where is the problem. Can you help me?
public void setdirectory(StringBuffer text)
{
String temp;
boolean t;
v.add(0,String.valueOf(text.charAt(0))); //A[0]=first letter in text.
for(int i=1;i<text.length();++i)
{
temp=String.valueOf(text.charAt(i));
try{
for(int j=0;j<v.capacity();++j)
{
if(!temp.equals(v.elementAt(j)))
{
v.add(i,temp);
}
v.trimToSize();
}
// System.out.println(v.capacity());
}catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("usage error");
}
}
}
If you're using Java 8+, then it might be simpler to use the new Stream API...
String str = "aabbc";
StringBuilder sb = new StringBuilder(str.length());
str.chars().distinct().forEach(c -> sb.append((char)c));
System.out.println(sb.toString());
Which prints
abc
I'd write a function to get unique characters, and assuming you need to preserve the insertion order, I'd use a LinkedHashSet<Character> and I'd prefer StringBuilder over StringBuffer. Something like
static String getUniqueCharacters(String text) {
Set<Character> set = new LinkedHashSet<>();
for (char ch : text.toCharArray()) {
set.add(ch);
}
StringBuilder sb = new StringBuilder();
for (char ch : set) {
sb.append(ch);
}
return sb.toString();
}
An alternative Java 8 solution is:
String str = "aabbc";
String str2 = str.chars().distinct().mapToObj(j->""+(char)j).collect(Collectors.joining());
System.out.println(str2);
Behind the scenes, this is similar to other answers here as IntStream::distinct is implemented using a LinkedHashSet<Integer>, and joining uses a StringBuilder.
You need to keep track of where you are adding your value in the vector. Also the number of objects in a vector is size(), not capacity() (look up the API for both; capacity() shows the current number of 'spaces' filled and available to fill before the vector needs to expand, it doesn't show how much of it has actually been filled).
Doh, and the third reason your code would not have worked: you were adding the character every time it found a non-matching one in the vector (over-writing itself each time so you would have only seen the last addition)
public void setdirectory(StringBuffer text) {
String temp;
boolean t;
int addAt = 0;
v.add(addAt,String.valueOf(text.charAt(0))); //A[0]=first letter in text.
for(int i=1;i<text.length();++i) {
temp=String.valueOf(text.charAt(i));
try {
boolean found = false
for(int j=0;j<v.size();++j) {
if(temp.equals(v.elementAt(j))) {
found = true;
break;
}
}
if (!found) {
addAt++;
v.add(addAt,temp);
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("usage error");
}
}
}
And although this would fix your code as it stands (which will be an important exercise for a beginner programmer), there are other ways of doing this that you should explore.
I am casting my String variables to integer and double. I want to check whether the String variable contains valid Integer or Double value at runtime.
I us following code but it not works for me.
String var1="5.5";
String var2="6";
Object o1=var1;
Object o2=var2;
if (o1 instanceof Integer)
{
qt += Integer.parseInt( var1);// Qty
}
if (o2 instanceof Double)
{
wt += Double.parseDouble(var2);// Wt
}
Try to parse the int and catch the exception if it fails:
String var1="5.5";
try {
qt += Integer.parseInt( var1);
}
catch (NumberFormatException nfe) {
// wasn't an int
}
You can use patterns to detect if a string is an integer or not :
Pattern pattern = Pattern.compile("^[-+]?\\d+(\\.\\d+)?$");
Matcher matcher = pattern.matcher(var1);
if (matcher.find()){
// Your string is a number
} else {
// Your string is not a number
}
You will have to find the correct pattern (I haven't used them for awhile) or someone could edit my answer with the correct pattern.
*EDIT** : Found a pattern for you. edited the code. I did not test it but it is taken from java2s site which also offer an even more elgant approach (copied from the site) :
public static boolean isNumeric(String string) {
return string.matches("^[-+]?\\d+(\\.\\d+)?$");
}
First of all, your if condition will certainly fail, because the object reference actually points to a String object. So, they are not instances of any integer or double.
To check whether a string can be converted to integer or double, you can either follow the approach in #Bedwyr's answer, or if you don't want to use try-catch, as I assume from your comments there (Actually, I don't understand why you don't want to use them), you can use a little bit of pattern matching: -
String str = "6.6";
String str2 = "6";
// If only digits are there, then it is integer
if (str2.matches("[+-]?\\d+")) {
int val = Integer.parseInt(str2);
qt += val;
}
// digits followed by a `.` followed by digits
if (str.matches("[+-]?\\d+\\.\\d+")) {
double val = Double.parseDouble(str);
wt += val;
}
But, understand that, Integer.parseInt and Double.parseDouble is the right way to do this. This is just an alternate approach.
Maybe regexps could suit your needs:
public static boolean isInteger(String s) {
return s.matches("[-+]?[0-9]+");
}
public static boolean isDouble(String s) {
return s.matches("[-+]?([0-9]+\\.([0-9]+)?|\\.[0-9]+)");
}
public static void main(String[] args) throws Exception {
String s1 = "5.5";
String s2 = "6";
System.out.println(isInteger(s1));
System.out.println(isDouble(s1));
System.out.println(isInteger(s2));
System.out.println(isDouble(s2));
}
Prints:
false
true
true
false
Integer.parseInt and Double.parseDouble return the integer/double value of the String. If the String is not a valid number, the method will thrown a NumberFormatException.
String var1 = "5.5";
try {
int number = Integer.parseInt(var1); // Will fail, var1 has wrong format
qt += number;
} catch (NumberFormatException e) {
// Do your thing if the check fails
}
try {
double number = Double.parseDouble(var1); // Will succeed
wt += number;
} catch (NumberFormatException e) {
// Do your thing if the check fails
}
There are some situation that I need to convert string to float or some other numerical data-type but there is a probability of getting some nonconvertible values such as "-" or "/" and I can't verify all the values beforehand to remove them.
and I want to avoid using try/catch for this matter , is there any other way of doing a proper conversion in java? something similar to C# TryParse?
The simplest thing I can think of is java.util.Scanner . However this approach requires a new Scanner instance for each String.
String data = ...;
Scanner n = new Scanner(data);
if(n.hasNextInt()){//check if the next chars are integer
int i = n.nextInt();
}else{
}
Next you could write a regex pattern that you use to check the String (complex to fail too big values) and then call Integer.parseInt() after checking the string against it.
Pattern p = Pattern.compile("insert regex to test string here");
String data = ...;
Matcher m = p.matcher(data);
//warning depending on regex used this may
//only check part of the string
if(m.matches()){
int i = Integer.parseInt(data);
}
However both of these parse the string twice, once to test the string and a second time to get the value. Depending on how often you get invalid strings catching an exception may be faster.
Unfortunately, there is no such method in Java. There is no out parameter in Java, so writing such a method would need to return a null Float to signal an error, or to pass a FloatHolder object which could be modified by the method:
public class FloatHolder {
private float value;
public void setValue(float value) {
this.value = value;
}
public float getValue() {
return this.value;
}
}
public static boolean tryParseFloat(String s, FloatHolder holder) {
try {
float value = Float.parseFloat(s);
holder.setValue(value);
}
catch (NumberFormatException e) {
return false;
}
}
This is an old question, but since all the answers fail to mention this (and I wasn't aware of it myself until seeing it in a merge request written by a colleague), I want to point potential readers to the Guava Floats and Ints classes:
With the help of these classes, you can write code like this:
Integer i = Ints.tryParse("10");
Integer j = Ints.tryParse("invalid");
Float f = Floats.tryParse("10.1");
Float g = Floats.tryParse("invalid.value");
The result will be null if the value is an invalid int or float, and you can then handle it in any way you like. (Be careful to not just cast it to an int/float, since this will trigger a NullPointerException if the value is an invalid integer/floating point value.)
Note that these methods are marked as "beta", but they are quite useful anyway and we use them in production.
For reference, here are the Javadocs for these classes:
https://google.github.io/guava/releases/snapshot-jre/api/docs/com/google/common/primitives/Ints.html
https://google.github.io/guava/releases/snapshot-jre/api/docs/com/google/common/primitives/Floats.html
Java does not provide some built in tryParse type of methods, on of the solutions you can try is to create your own tryParse Method and put try/catch code in this method and then you can easily use this method across your application very easily and without using try/catch at all the places you use the method.
One of the sample functions can have following code
public static Long parseLong(String value) {
if(isNullOrEmpty(value)) {
return null;
}
try {
return Long.valueOf(value);
}
catch (NumberFormatException e) {
}
return null;
}
Regular expressions helped me solve this issue. Here is how:
Get the string input.
Use the expression that matches one or more digits.
Parse if it is a match.
String s = "1111";
int i = s.matches("^[0-9]+$") ? Integer.parseInt(s) : -1;
if(i != -1)
System.out.println("Integer");
else
System.out.println("Not an integer");
What is the most elegant way to convert a hyphen separated word (e.g. "do-some-stuff") to the lower camel-case variation (e.g. "doSomeStuff") in Java?
Use CaseFormat from Guava:
import static com.google.common.base.CaseFormat.*;
String result = LOWER_HYPHEN.to(LOWER_CAMEL, "do-some-stuff");
With Java 8 there is finally a one-liner:
Arrays.stream(name.split("\\-"))
.map(s -> Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase())
.collect(Collectors.joining());
Though it takes splitting over 3 actual lines to be legible ツ
(Note: "\\-" is for kebab-case as per question, for snake_case simply change to "_")
The following method should handle the task quite efficient in O(n). We just iterate over the characters of the xml method name, skip any '-' and capitalize chars if needed.
public static String toJavaMethodName(String xmlmethodName) {
StringBuilder nameBuilder = new StringBuilder(xmlmethodName.length());
boolean capitalizeNextChar = false;
for (char c:xmlMethodName.toCharArray()) {
if (c == '-') {
capitalizeNextChar = true;
continue;
}
if (capitalizeNextChar) {
nameBuilder.append(Character.toUpperCase(c));
} else {
nameBuilder.append(c);
}
capitalizeNextChar = false;
}
return nameBuilder.toString();
}
Why not try this:
split on "-"
uppercase each word, skipping the first
join
EDIT: On second thoughts... While trying to implement this, I found out there is no simple way to join a list of strings in Java. Unless you use StringUtil from apache. So you will need to create a StringBuilder anyway and thus the algorithm is going to get a little ugly :(
CODE: Here is a sample of the above mentioned aproach. Could someone with a Java compiler (sorry, don't have one handy) test this? And benchmark it with other versions found here?
public static String toJavaMethodNameWithSplits(String xmlMethodName)
{
String[] words = xmlMethodName.split("-"); // split on "-"
StringBuilder nameBuilder = new StringBuilder(xmlMethodName.length());
nameBuilder.append(words[0]);
for (int i = 1; i < words.length; i++) // skip first
{
nameBuilder.append(words[i].substring(0, 1).toUpperCase());
nameBuilder.append(words[i].substring(1));
}
return nameBuilder.toString(); // join
}
If you don't like to depend on a library you can use a combination of a regex and String.format. Use a regex to extract the starting characters after the -. Use these as input for String.format. A bit tricky, but works without a (explizit) loop ;).
public class Test {
public static void main(String[] args) {
System.out.println(convert("do-some-stuff"));
}
private static String convert(String input) {
return String.format(input.replaceAll("\\-(.)", "%S"), input.replaceAll("[^-]*-(.)[^-]*", "$1-").split("-"));
}
}
Here is a slight variation of Andreas' answer that does more than the OP asked for:
public static String toJavaMethodName(final String nonJavaMethodName){
final StringBuilder nameBuilder = new StringBuilder();
boolean capitalizeNextChar = false;
boolean first = true;
for(int i = 0; i < nonJavaMethodName.length(); i++){
final char c = nonJavaMethodName.charAt(i);
if(!Character.isLetterOrDigit(c)){
if(!first){
capitalizeNextChar = true;
}
} else{
nameBuilder.append(capitalizeNextChar
? Character.toUpperCase(c)
: Character.toLowerCase(c));
capitalizeNextChar = false;
first = false;
}
}
return nameBuilder.toString();
}
It handles a few special cases:
fUnnY-cASe is converted to funnyCase
--dash-before-and--after- is converted to dashBeforeAndAfter
some.other$funky:chars? is converted to someOtherFunkyChars
For those who has com.fasterxml.jackson library in the project and don't want to add guava you can use the jaskson namingStrategy method:
new PropertyNamingStrategy.SnakeCaseStrategy.translate(String);
get The Apache commons jar for StringUtils. Then you can use the capitalize method
import org.apache.commons.lang.StringUtils;
public class MyClass{
public String myMethod(String str) {
StringBuffer buff = new StringBuffer();
String[] tokens = str.split("-");
for (String i : tokens) {
buff.append(StringUtils.capitalize(i));
}
return buff.toString();
}
}
As I'm not a big fan of adding a library just for one method, I implemented my own solution (from camel case to snake case):
public String toSnakeCase(String name) {
StringBuilder buffer = new StringBuilder();
for(int i = 0; i < name.length(); i++) {
if(Character.isUpperCase(name.charAt(i))) {
if(i > 0) {
buffer.append('_');
}
buffer.append(Character.toLowerCase(name.charAt(i)));
} else {
buffer.append(name.charAt(i));
}
}
return buffer.toString();
}
Needs to be adapted depending of the in / out cases.
In case you use Spring Framework, you can use provided StringUtils.
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.stream.Collectors;
public class NormalizeUtils {
private static final String DELIMITER = "_";
private NormalizeUtils() {
throw new IllegalStateException("Do not init.");
}
/**
* Take name like SOME_SNAKE_ALL and convert it to someSnakeAll
*/
public static String fromSnakeToCamel(final String name) {
if (StringUtils.isEmpty(name)) {
return "";
}
final String allCapitalized = Arrays.stream(name.split(DELIMITER))
.filter(c -> !StringUtils.isEmpty(c))
.map(StringUtils::capitalize)
.collect(Collectors.joining());
return StringUtils.uncapitalize(allCapitalized);
}
}
Iterate through the string. When you find a hypen, remove it, and capitalise the next letter.