I'm trying to find out if the input of the user is decimal or fraction or mixed fraction and when there is a decimal with fraction I would like to replace the decimal to a whole number so that it would be a proper mixed fraction
for example:
input: 2.23 1/2
expected output: 2 1/2
public class DecimalOrFraction {
public static void main(String args[]){
String partOfString;
String[] s = { "0000.2","2","2.222 1/2","1 2/2", "0"};
for (int x = 0 ;x<s.length;x++) {
if(s[x].matches("[1-9]{1}\\d{0,3}([.]\\d{1,3}\\s{0,1})?")){
System.out.println(x+") "+Float.valueOf(s[x])+" ---- Decimal");
}
else if(s[x].matches("[1-9]{1,5}([.]\\d{1,3})?\\s[1-9]{1}\\d{0,2}([/]\\d{0,3})?")){
partOfString = s[x].substring( s[x].lastIndexOf("."), s[x].lastIndexOf(" ")); //HAVING AN ERROR
s[x] = s[x].replace(partOfString," ");
System.out.println(x+") "+s[x]+" ---- Fraction");
}
else if(s[x].matches("[1-9]\\d{0,4}[/]\\d{0,3}")){
System.out.println(x+") "+s[x]+" ---- also Fraction");
}
else{
System.out.println(x+") "+s[x]+" ---- ERROR/Zero");
}
}
}
}
Is there another way to make this work without any error??
The error occurs because there is no dot in "1 2/2" to take the index of.
Since the matching uses RegEx, why not use RegEx for the replacement as well?
Here's a pass at refactoring the whole thing.
private static final Pattern DECIMAL = Pattern.compile("\\d*\\.?\\d+");
private static final Pattern FRACTION = Pattern.compile("\\.\\d+(\\s+\\d+/\\d+)");
public static void main(String args[]) {
String[] samples = {"0000.2", "2", "2.222 1/2", "1 2/2", "0"};
for (String sample : samples) {
if (DECIMAL.matcher(sample).matches()) {
float decimal = Float.parseFloat(sample);
System.out.println(decimal + (decimal == 0 ? "\tERROR/Zero" : "\tDecimal"));
}
else {
String fraction = FRACTION.matcher(sample).replaceFirst("$1");
System.out.println(fraction + "\tFraction");
}
}
}
if you can ONLY have at most two separate parts then you can use String.split() and split on a " " white space. Then if you have two parts it's easier to work with. If you have one, again, simple conditionals. I don't think there's a need for this much messy regex.
Alterantively, if you have more than one whitespace, simply call each resulting split string against a regex for either of your two cases and handle that way.
Related
I would like to be able to go through an inputted string and count the amount of times "good" is written and compare it to how many times "bad" is written. If the good and the bad match, then goodVbad==0 and it returns true. Otherwise it returns false.
The code worked fine when I was using if statements inside the for-loop, but when using the ternary operator it doesn't. While debugging, I realized that each time the for-loop moves onto the next element 'goodVbad' becomes zero again. Kind of stumped, would love some advice. Thanks!
public static boolean goodbadClean(String word) {
String [] wordS;
int goodVbad=0;
String good="good";
String bad="bad";
word=word.toLowerCase();
word=word.replaceAll(good, " good ");
word=word.replaceAll(bad, " bad ");
wordS=word.split(" ");
for(String i:wordS) {
goodVbad=i.equals(good)?goodVbad++
:i.equals(bad) ?goodVbad--
:goodVbad;
}
if(goodVbad==0) {
return true;
}
return false;
}
The problem is the postfix ++ operator returns the old value, which you are assigning the variable, then increments. ie
goodVBad = goodVBad++; // returns the old value, so does nothing
so you should use the prefixed ++ operator:
goodVBad = ++goodVBad; // increments first, returning the new value
But both of these are hard to read and brittle.
If you must use ternaries, change your code to:
goodVbad += i.equals(good) ? 1 : (i.equals(bad) ? -1 : 0);
However, nested ternaries are generally a style smell. I recommend instead:
if (i.equals(good)) {
goodVBad++;
} else if (i.equals(bad)) {
goodVBad--;
}
Assuming that the OP needs to count the frequency of a string pattern in a given string, then you could do something like this with Java 8 or older:
public class CountMatches {
public static void main(String[] args) {
String phrase1 = "goodbadbadgoodgoodbad"; // equal amount of good vs bad.
String phrase2 = "goodbadbadgoodgoodbadbad"; // more bad than good.
String phrase3 = "goodbadbadgoodgoodbadgood"; // more good than bad.
// create capturing groups for "good" and "bad"
String GOOD_REGEX = "(good)";
String BAD_REGEX = "(bad)";
Pattern gPattern = Pattern.compile(GOOD_REGEX);
Pattern bPattern = Pattern.compile(BAD_REGEX);
Matcher countGood = gPattern.matcher(phrase1);
Matcher countBad = bPattern.matcher(phrase1);
int count = 0;
while (countBad.find()) {
count--;
}
while (countGood.find()) {
count++;
}
System.out.println(count == 0);
}
}
With Java 9 or later:
public class CountMatches {
public static void main(String[] args) {
String phrase1 = "goodbadbadgoodgoodbad"; // equal amount of good vs bad.
String phrase2 = "goodbadbadgoodgoodbadbad"; // more bad than good.
String phrase3 = "goodbadbadgoodgoodbadgood"; // more good than bad.
String GOOD_REGEX = "(good)";
String BAD_REGEX = "(bad)";
Pattern gPattern = Pattern.compile(GOOD_REGEX);
Pattern bPattern = Pattern.compile(BAD_REGEX);
Matcher countGood = gPattern.matcher(phrase1);
Matcher countBad = bPattern.matcher(phrase1);
long cCount = countGood.results().count();
long bCount = countBad.results().count();
System.out.println(cCount - bCount == 0);
}
}
My assumption is based on this line of code word=word.replaceAll(good, " good ");. This tells me that the expected input is something similar to the phrase variables I used for my testing.
By the way, this solution should work even if the words "good" and/or "bad" are preceded or followed by spaces.
UPDATE: Integrated looping to evaluate all expressions against all phrases.
public static void main(String[] args) {
List<String> expressions = List.of("(good)", "(bad)");
List<String> phrases = List.of("goodbadbadgoodgoodbad", "goodbadbadgoodgoodbadbad", "goodbadbadgoodgoodbadgood", " good bad bad good good bad ");
for (String phrase : phrases) {
List<Long> itemCount = new ArrayList<>();
for (String regex : expressions) {
Pattern gPattern = Pattern.compile(regex);
Matcher matcher = gPattern.matcher(phrase);
long count = matcher.results().count();
System.out.println("Pattern \"" + regex + "\" appears " + count + (count == 1 ? " time" : " times"));
itemCount.add(count);
}
long count = itemCount.stream().reduce((value1, value2) -> value1 - value2).get();
System.out.println(count == 0);
}
}
This outputs:
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 3 times
true
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 4 times
false
Pattern "(good)" appears 4 times
Pattern "(bad)" appears 3 times
false
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 3 times
true
I am fairly new to programming and regex is very confusing. I am trying to identify a data line that consists of 3 doubles with spaces in between for example:
500.00 56.48 500.00
I have tried this:
data.matches("^[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+$")
But this doesn't recognize the line. What am I doing wrong?
Don't do it the way you have tried.
Although the regex pattern you have used works for the numbers you have used, it will fail for a wide range of numbers e.g. .5 or 5.6E2 which are also double numbers.
Given below is the demo with your data and pattern:
public class Main {
public static void main(String[] args) {
String data = "500.00 56.48 500.00";
System.out.println(data.matches("^[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+$"));
}
}
Output:
true
However, it will fail to give you the expected result in the following case:
public class Main {
public static void main(String[] args) {
String data = ".5 5.6E2 500.00";
System.out.println(data.matches("^[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+\\s[0-9]+\\.[0-9]+$"));
}
}
Output:
false
Even though .5 and 5.6E2 are valid double numbers, your pattern failed to recognize them.
The recommended way:
You should split the data line on whitespace and try to parse each number using Double#parseDouble e.g.
public class Main {
public static void main(String[] args) {
String data = "500.00 56.48 500.00";
System.out.println(matches(data));
data = ".5 5.6E2 500.00";
System.out.println(matches(data));
data = ".5 500.00";
System.out.println(matches(data));
data = ".5 abc 500.00";
System.out.println(matches(data));
}
static boolean matches(String data) {
String[] nums = data.split("\\s+");
boolean match = true;
if (nums.length == 3) {
for (String num : nums) {
try {
Double.parseDouble(num);
} catch (NumberFormatException e) {
match = false;
break;
}
}
} else {
match = false;
}
return match;
}
}
Output:
true
true
false
false
Improve your regex by observing a few things:
[0-9] is the same as \d
you're looking for the same pattern, thrice
So, let's do that:
three times:
one or more numbers, optionally followed by
a period and then one or more numbers, optionally followed by
white space
Which means:
(...){3} where ... is:
\d+, optionally followed by
(\.\d+)? (i.e. zero-or-once), optionally followed by
\s* (zero-or-more)
Putting that all together, and remembering to use proper string escaping:
data.matches("^(\\d+(\\.\\d+)?\\s*){3}$")
You can see this working over on https://regex101.com/r/PGxAm9/1, and keeping regex101 bookmarked for future debugging is highly recommended.
This question already has answers here:
Split the string on forward slash
(4 answers)
Closed 2 years ago.
I really need a regex expert:
I need a regex expression (in java) for splitting this examples:
Hello/World (word/word) => Hello,World
Hello/12 (word/number) => Hello,12
15/Hello (number/word) => 15,Hello
12/17 (number/number) => 12/17 (Do not split)
Update:
This is what I tried but it also mark the number/number option
https://regex101.com/r/zZ9nO5/2
Thanks
It might not be the most elegant solution but for your requirement you can do it like that:
(([a-zA-Z]+?)/([a-zA-Z]+))|(([a-zA-Z]+?)/([\d]+))|(([\d]+?)/([a-zA-Z]+))
It's a check for word / word, word / number and number / word
replace with the corresponding groups found \2\5\8,\3\6\9
A simple java program for that would be:
public static void main(String[] args) {
String[] stringArray=new String[]{"Hello/World","Hello/12","15/Hello","12/17"};
for(String s:stringArray) {
System.out.println(s.replaceAll("(([a-zA-Z]+?)/([a-zA-Z]+))|(([a-zA-Z]+?)/([\\d]+))|(([\\d]+?)/([a-zA-Z]+))", "$2$5$8,$3$6$9"));
}
}
Result is:
Hello,World
Hello,12
15,Hello
12/17
Slightly different approach, but you could check the characters in the String to see that they all are either a number or a forward slash, and then split if necessary:
public static void main(String[] args) {
String[] strArray = new String[]{"Hello/World", "Hello/12", "15/Hello", "12/17"};
for(String str: strArray){
if(checkIfValid(str)){
System.out.println(str);
}
else{
System.out.println(str.replace("/", ","));
}
}
}
public static boolean checkIfValid(String str) {
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i)) && str.charAt(i) != '/') {
return false;
}
}
return true;
}
Output:
Hello,World
Hello,12
15,Hello
12/17
This might help if Hello12/15 is not supposed to be split.
A little more context would be nice but as I understand it, you get a string with a single '/' in the middle and you either replace the '/' with ',' or you dont if it has numbers on both sides.
So i would do something like this:
public class MyClass {
public static void main(String args[]) {
String mystring = "12/25";
if(!mystring.matches("^\\d+\\/\\d+$"))
mystring = mystring.replace("/", ",");
System.out.println(mystring);
}
}
If that is what you wanted to do here, then I belive its less complicated and also quicker than a big regex destinguishing between all 4 cases.
import java.util.Scanner;
public class CashSplitter {
public static void main(String[] args) {
Scanner S = new Scanner(System.in);
System.out.println("Cash Values");
String i = S.nextLine();
for(int b = 0;b<i.length(); b ++){
System.out.println(b);
System.out.println(i.substring(0,i.indexOf('.')+3));
i.replace(i.substring(0, i.indexOf('.') + 3), "");
System.out.println(i);
System.out.println(i.substring(0, i.indexOf('.') + 3));
}
}
}
The code should be able to take a string with multiple cash values and split them up, into individual values. For example 7.32869.32 should split out 7.32, 869.32 etc
A string is immutable, therefore replace returns a new String for you to use
try
i = i.replace(i.substring(0, i.indexOf('.') + 3), "");
Although try using
https://docs.oracle.com/javase/7/docs/api/java/text/NumberFormat.html
There are several problems with your code:
You want to add two, not three, to the index of the decimal point,
You cannot use replace without assigning back to the string,
Your code assumes that there are no identical cash values.
For the last point, if you start with 2.222.222.22, you would get only one cash value instead of three, because replace would drop all three matches.
Java offers a nice way of splitting a String on a regex:
String[] parts = S.split("(?<=[.]..)")
Demo.
The regex is a look-behind that expects a dot followed by any two characters.
I'm currently stuck on a problem from CodeAbbey. I don't want an answer to the entire thing.
This is the meat of the question:
Input data will have:
initial integer number in the first line;
one or more lines describing operations, in form sign value where sign is either + or * and value is an integer;
last line in the same form, but with sign % instead and number by which the result should be divided to get the remainder.
Answer should give remainder of the result of all operations applied sequentially (starting with initial number) divided by the last number.
My problem is with the logic. So far I realize there is an operator, a space and then a number. To get the number I thought of using
char c = src.charAt(2);
and to get the operator I'd use the same thing. Then I'd just use a bunch of if-else statements to figure out the rest. But how do I do this in the large scale? How do I read all of those numbers in and do it for every one of them? A nudge on the right direction would help.
import java.util.Scanner;
public class Challenge14 {
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Enter Your first number: ");
int x = in.nextInt();
for (int i = 0; i < 7; i++) {
String[] s = new String[i];
s = in.nextLine();
}
}
}
One of the more helpful classes for this problem is the Scanner.
The Scanner documentation is located at:
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
The Scanner can be set to read from a String, File, or Input Stream.
The Scanner has several useful methods, including:
hasNext(), which lets you know if there are any other operators or numbers to pick up
next(), which will read the next token as a String
nextInt(), which will read the next token as an int
You can use the scanner to pick up the first number, then use some sort of loop to perform operations on that number until there are no more operations to perform.
Assuming that the input is from a file, what you want to do is this:
Read the first line in as a number
Split the input on each other line on whitespace, so you're left with something that can be interpreted as an operator, and something that can be interpreted as a number
Perform the operations and accumulate your result
The file portion is likely what you're struggling with. The answer below addresses that. I leave the rest as an exercise for the reader.
public class Accumulator {
private int result;
public void readFile(String filename) {
try(Scanner scan = new Scanner(new File(filename)) {
// Unconditionally read the first line as a number
result += Integer.parseInt(scan.nextLine());
//Now, we need to read in each other line remaining.
while(scan.hasNextLine()) {
String[] contents = scan.nextLine().split();
int number = Integer.parseInt(contents[1]);
// The operator is in contents[0]
performArithmeticWith(contents[0], number);
}
} catch(IOException e) {
e.printStackTrace();
}
}
public void performArithmeticWith(String operator, int number) {
switch(operator) {
case "+":
break;
// etc
}
}
}
My problem is with the logic. So far I realize there is an operator, a space and then a number.
There are several options in Java to separate the operator and the operand.
You can use the String.split() method:
String[] token input.split(" ");
//token[0] will be your operator
//token[1] will be your number
You can also use the indexOf() method:
int idx = input.indexOf(" ");
String opr = input.substring(0, idx); //your operator
String num = input.substring(idx+1); //your number
This is my approach.
Assumption is that you will get all the values as String array (Which
I believe is much easy compare to making a scalable solution).
Here's my code. You can support additional operators easily and the sequence of operator does not matter.
package com.stack.overflow.test;
import java.math.BigDecimal;
public class Calculator {
public static void main(String[] args) {
String[] values = {"5", "+", "3", "*", "7", "+", "10", "*", "2", "*", "3", "+", "1", "%", "11"};
new Calculator().calculate(values);
}
public void calculate(String[] inputs) {
BigDecimal result = null;
for(int i = 0; i < inputs.length-2;) {
String left = inputs[i];
String operator = inputs[++i];
String right = inputs[++i];
System.out.println("left : "+ left);
System.out.println("operator : "+ operator);
System.out.println("right : "+ right);
result = Operator.instanceOf(operator).apply(new BigDecimal(left), new BigDecimal(right));
inputs[i] = result.toString();
System.out.println("Result :: "+ result);
}
}
}
enum Operator {
ADD("+") {
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.add(right);
}
},
MULTIPLY("*"){
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.multiply(right);
}
},
REMAINDER("%"){
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.remainder(right);
}
};
private String symbol;
Operator(String symbol) {
this.symbol = symbol;
}
public static Operator instanceOf(String givenSymbol) {
for(Operator operator : Operator.values()) {
if(operator.symbol.equals(givenSymbol)) {
return operator;
}
} throw new RuntimeException("Operator not supported : "+givenSymbol);
}
abstract BigDecimal apply(BigDecimal left, BigDecimal right);
}
Result
left : 5
operator : +
right : 3
Result :: 8
left : 8
operator : *
right : 7
Result :: 56
left : 56
operator : +
right : 10
Result :: 66
left : 66
operator : *
right : 2
Result :: 132
left : 132
operator : *
right : 3
Result :: 396
left : 396
operator : +
right : 1
Result :: 397
left : 397
operator : %
right : 11
Result :: 1
The input data contains a number at the first line. Then an operation and a number delimited by a space on each consecutive line. Here is one approach to read in the data.
First, read the data line by line, until there are no more lines. Since there is only one element on the first line, read it and convert it to an integer (it looks like all data is integers). A Scanner can be used to read the data line by line. The two useful methods here are:
public boolean hasNextLine() - Returns true if there is another line in the input of this scanner.
public String nextLine() - Advances this scanner past the current line and returns the input that was skipped.
For each line after that, read it, and split it based on the white space using String[] splited = str.split("\\s+");. Then process the string, and read the next line. Note that split, splits based on white space by default and "\\s+" is there just for explicitness.