Java regular expression prompt error character [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Usually, a regular expression can only indicate whether the statement and the rule match. I want to be able to indicate the wrong character when I'm not, what should I do。
Pattern compile = Pattern.compile("[a-zA-Z]*");
Matcher matcher = compile.matcher("abc1ac");
I want to make an error in the character 1.
I want to check a filter,like (name eq '1' or nickname ne '2') and code like '''' and user.name like 'jo%', the value using double '' translation

I write as follow,maybe better to use design pattern.
public class FilterExpressionException extends RuntimeException {
private String expression;
private int index;
public FilterExpressionException(String expression, int index) {
super(mark(expression, index));
this.expression = expression;
this.index = index;
}
public FilterExpressionException(String message, String expression, int index) {
super(message + "(" + mark(expression, index) + ")");
this.expression = expression;
this.index = index;
}
private static String mark(String expression, int index) {
return expression.substring(0, index) + '^' + expression.substring(index);
}
public String getExpression() {
return expression;
}
public int getIndex() {
return index;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class FilterExpressionParserImpl {
private String[] relations = {"eq", "ne", "gt", "ge", "lt", "le", "like", "in", "bt"};
private String[] logices = {"and", "or"};
private char[][] relationChars = toCharArray(relations);
private char[][] logicChars = toCharArray(logices);
public static void main(String[] args) {
FilterExpressionParserImpl impl = new FilterExpressionParserImpl();
String expr = "(name eq '' or nickname ne '2' ) and (code like '''' or (user.A.name eq '''go''go''go'))";
List<String> parse = impl.parse(expr);
System.out.println(parse);
List<String> strings = impl.followUp(parse);
System.out.println(strings);
}
private class Variable {
Stack<String> words = new Stack<>();
Stack<Character> characters = new Stack<>();
Stack<Integer> brackets = new Stack<>();
int step = 0;
char character;
int commaTimes = 0;
char[][] relations;
char[][] logices;
public Variable(char[][] relations, char[][] logices) {
this.relations = relations;
this.logices = logices;
}
}
private List<String> followUp(List<String> middles) {
List<String> afters = new ArrayList<>(middles.size());
Stack<String> operators = new Stack<>();
String top;
for (String middle : middles) {
switch (middle) {
case "and":
case "or":
if (operators.size() > 0 && !operators.peek().equals("(")) afters.add(operators.pop());
operators.push(middle);
break;
case "(":
operators.push(middle);
break;
case ")":
while (!(top = operators.pop()).equals("(")) afters.add(top);
break;
default:
afters.add(middle);
}
}
while (!operators.isEmpty()) afters.add(operators.pop());
return afters;
}
private List<String> parse(String filter) {
filter = filter.trim();
Variable variable = new Variable(relationChars, logicChars);
for (int i = 0; i < filter.length(); i++) {
variable.character = filter.charAt(i);
switch (variable.character) {
case ' ':
if (variable.characters.isEmpty()) continue;
switch (variable.step) {
case 0:
dealPropertyPathEnd(filter, i, variable);
break;
case 1:
dealRelationEnd(variable);
break;
case 2:
dealValueEnd(filter, i, variable);
break;
case 3:
dealLogicEnd(variable);
break;
}
pushWord(variable);
break;
case '(':
if (variable.step != 0) throw new FilterExpressionException(filter, i);
variable.words.push(String.valueOf(variable.character));
variable.brackets.push(i);
break;
case ')':
if (variable.brackets.size() == 0) throw new FilterExpressionException(filter, i);
variable.brackets.pop();
if (variable.step == 2 && !variable.characters.isEmpty()) {
dealValueEnd(filter, i, variable);
pushWord(variable);
}
if (variable.step != 3) throw new FilterExpressionException(filter, i);
variable.words.push(String.valueOf(variable.character));
break;
default:
switch (variable.step) {
case 0:
if (!(isLetter(variable.character) || variable.character == '.')
|| ((variable.characters.size() == 0 || variable.characters.peek() == '.') && variable.character == '.'))
throw new FilterExpressionException(filter, i);
break;
case 1:
variable.relations = find(variable.relations, variable.characters.size(), variable.character);
if (variable.relations == null) throw new FilterExpressionException(filter, i);
break;
case 2:
if (variable.characters.size() == 0) {
if (variable.character != '\'') throw new FilterExpressionException(filter, i);
}
else {
if (variable.character == '\'') variable.commaTimes++;
else if (variable.commaTimes % 2 != 0) throw new FilterExpressionException(filter, i);
}
break;
case 3:
variable.logices = find(variable.logices, variable.characters.size(), variable.character);
if (variable.logices == null) throw new FilterExpressionException(filter, i);
break;
}
variable.characters.push(variable.character);
break;
}
}
if (!variable.characters.isEmpty()) {
if (variable.characters.peek() != '\'') throw new FilterExpressionException(filter, filter.length() - 1);
if (variable.commaTimes % 2 != 1) throw new FilterExpressionException(filter, filter.length() - 1 - variable.commaTimes);
pushWord(variable);
}
if (!variable.brackets.isEmpty()) throw new FilterExpressionException(filter, variable.brackets.firstElement());
return variable.words;
}
private void pushWord(Variable variable) {
String string = join(variable.characters);
if (variable.step == 3) {
if (string.equals("\'\'")) {
string = "";
} else {
string = string.replace("\'\'", "\'");
string = string.substring(1, string.length() - 1);
}
}
variable.words.push(string);
variable.characters.clear();
}
private String join(List<Character> characters) {
StringBuilder builder = new StringBuilder();
characters.forEach(builder::append);
return builder.toString();
}
private void dealPropertyPathEnd(String filter, int i, Variable variable) {
if (variable.characters.peek() == '.') throw new FilterExpressionException(filter, i);
variable.step = 1;
}
private void dealRelationEnd(Variable variable) {
variable.relations = relationChars;
variable.step = 2;
}
private void dealValueEnd(String filter, int i, Variable variable) {
if (variable.characters.peek() != '\'') throw new FilterExpressionException(filter, i);
if (variable.commaTimes % 2 != 1) throw new FilterExpressionException(filter, i);
variable.commaTimes = 0;
variable.step = 3;
}
private void dealLogicEnd(Variable variable) {
variable.logices = logicChars;
variable.step = 0;
}
private boolean isLetter(char character) {
return ('a' <= character && character <= 'z') || ('A' <= character && character <= 'Z');
}
private char[][] toCharArray(String[] strings) {
char[][] chars = new char[strings.length][];
for (int i = 0; i < strings.length; i++) {
chars[i] = strings[i].toCharArray();
}
return chars;
}
private char[][] find(char[][] sources, int column, char character) {
if (sources == null || sources.length == 0) return sources;
List<Integer> indexes = new ArrayList<>(sources.length);
for (int i = 0; i < sources.length; i++) {
if (sources[i].length > column && sources[i][column] == character) indexes.add(i);
}
if (indexes.isEmpty()) return null;
char[][] targets = new char[indexes.size()][];
for (int i = 0; i < indexes.size(); i++) {
targets[i] = sources[indexes.get(i)];
}
return targets;
}
}

Java's regular expression engine can do much more than just matching text. For more information, read the documentation.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LookingAt {
public static String validate(String input, Pattern regex) {
Matcher m = regex.matcher(input);
if (m.matches())
return "OK";
if (m.lookingAt())
return "First error at index " + m.end();
if (m.hitEnd())
return "Too short";
return "Cannot match at all";
}
public static void main(String[] args) {
System.out.println(validate("abcac", Pattern.compile("[a-zA-Z]*")));
System.out.println(validate("abc1ac", Pattern.compile("[a-zA-Z]*")));
System.out.println(validate("abcac", Pattern.compile("[a-zA-Z]{10,}")));
System.out.println(validate("1abcac", Pattern.compile("[a-zA-Z]+")));
}
}

Related

Dice formula evaluator

I wrote a couple of functions that take a formatted string, defines the number of dice and the size of the dice, throw them, and adds their values.
Eg: 3d8 would mean to throw 3 dices of 8 sides each and add their values. The values are always positive, so every time I run this function for 3d8 I could get values between 3 and 24.
public int calcDice(String diceFormula){
String[] divided = diceFormula.split("d");
int cant = Integer.parseInt(divided[0]);
int dice = Integer.parseInt(divided[1]);
int result = 0;
for (int i = 0; i < cant; i++) {
result += throwDice(dice);
}
return result;
}
private int throwDice(int diceSize) {
diceSize = diceSize < 0 ? dice * -1 : diceSize;
Random r = new Random();
return r.nextInt((diceSize - 1) + 1) + 1;
}
What I require now, is to be able to make mathematical functions using these values, so I could input a mathematical function that will be calculated. I would need to respect the resolution order
Eg. ((3d8)+1) x (2d4) x 3
One of the ideas was to take the string and process first the values, then replace the javascript evaluator to figure out the result, but I'm not sure how can I "pick" the values.
(A regex maybe?)
What I did to solve this was to implement a ShuntingYard function that was able to parse mathematical expressions
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ShuttingYard {
private final Map<String, Integer> operators = new HashMap<>();
public ShuttingYard(){
operators.put("-", 0);
operators.put("+", 0);
operators.put("/", 1);
operators.put("*", 1);
operators.put("^", 2);
}
public double doTheShuntingYard(String expression)throws IllegalArgumentException, NumberFormatException, ArithmeticException{
if(expression == null || expression.trim().length() == 0)
throw new IllegalArgumentException("Empty expression or null");
expression = expression.replaceAll("\\s+","");
expression = expression.replace("(-", "(0-");
if (expression.startsWith("-")){
expression = "0" + expression;
}
Pattern pattern = Pattern.compile("((([0-9]*[.])?[0-9]+)|([\\+\\-\\*\\/\\(\\)\\^]))");
Matcher matcher = pattern.matcher(expression);
int counter = 0;
List<String> tokens = new ArrayList<>();
while(matcher.find()){
if(matcher.start() != counter){
throw new IllegalArgumentException("Invalid Expression:" + expression + ". Error between " + counter+ " end " + matcher.start());
}
tokens.add(matcher.group().trim());
counter += tokens.get(tokens.size() - 1 ).length();
}
if(counter != expression.length()){
throw new IllegalArgumentException("Invalid end of expression");
}
Stack<String> stack = new Stack<>();
List<String> output = new ArrayList<>();
for(String token : tokens){
if(operators.containsKey(token)){
while(!stack.empty() &&
operators.containsKey(stack.peek())&&
((operators.get(token) <= operators.get(stack.peek()) && !token.equals("^"))||
(operators.get(token) < operators.get(stack.peek()) && token.equals("^")))){
output.add(stack.pop());
}
stack.push(token);
}
else if(token.equals("(")){
stack.push(token);
}
else if(token.equals(")")){
while(!stack.empty()){
if(!stack.peek().equals("(")){
output.add(stack.pop());
}
else{
break;
}
}
if(!stack.empty()){
stack.pop();
}
}
else{
output.add(token);
}
}
while(!stack.empty()){
output.add(stack.pop());
}
Stack<Double> doubles = new Stack<>();
for(String token : output){
if(!operators.containsKey(token) && token.matches("([0-9]*[.])?[0-9]+")){
try{
doubles.push(Double.parseDouble(token));
}
catch(NumberFormatException n){
throw n;
}
}
else{
if(doubles.size() > 1){
double op1 = doubles.pop();
double op2 = doubles.pop();
switch (token) {
case "+":
doubles.push(op2 + op1);
break;
case "-":
doubles.push(op2 - op1);
break;
case "*":
doubles.push(op2 * op1);
break;
case "/":
if(op1 == 0){
throw new ArithmeticException("Division by 0");
}
doubles.push(Math.floor(op2 / op1));
break;
case "^":
doubles.push(Math.pow(op2, op1));
break;
default:
throw new IllegalArgumentException(token + " is not an operator or is not handled");
}
}
}
}
if(doubles.empty() || doubles.size() > 1){
throw new IllegalArgumentException("Invalid expression, could not find a result. An operator seems to be absent");
}
return doubles.peek();
}
}
Then, I would call this function after resolving the throwDice operations
public class DiceThrower{
private ShuttingYard shuttingYard;
public DiceThrower(){
this.shuttingYard = new ShuttingYard();
}
public void throwDiceAction(View view){
TextView result = findViewById(R.id.diceResult);
try{
String original = ((EditText)findViewById(R.id.formula)).getText().toString();
Pattern pattern = Pattern.compile("([0-9]{1,999})d([0-9]{1,999})");
Matcher matcher = pattern.matcher(original);
while(matcher.find()){
original = matcher.replaceFirst(Integer.toString(calcDice(matcher.group(0))));
matcher = pattern.matcher(original);
}
result.setText(evaluateExpression(original).split("\\.")[0]);
}catch(ArithmeticException e){
result.setText("This doesn't seem to be a valid mathematical expression");
}
}
public String evaluateExpression(String expression){
expression = expression.replaceAll("\\)\\(", ")*(");
expression = expression.replaceAll("x", "*");
return Double.toString(this.shuttingYard.doTheShuntingYard(expression));
}
public int calcDice(String formula){
String[] divided = formula.split("d");
int cant = Integer.parseInt(divided[0]);
int dice = Integer.parseInt(divided[1]);
int result = 0;
for (int i = 0; i < cant; i++) {
result += throwDice(dice);
}
return result;
}
private int throwDice(int dice) {
dice = dice < 0 ? dice * -1 : dice;
Random r = new Random();
return r.nextInt((dice - 1) + 1) + 1;
}
}

Improvise the code against test cases where code fails

I wrote below code and i want to identify the test cases where my code fails.I want to identify the possible test cases where my test case failed. so i will improvise the same, in addition I also want to enhance it, meaning,also suggest me the best practice to improve performance.
At last, In the below code I have one method returnFinalComplement(String reverseStr) which return the complement, for calculating complement I have two Approaches, both are doing the same job, I am currenlty using approach-1, but i want to know about approach-2, which approach can pass all the test cases .
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
class DNAString {
private final static Character[] DATASET = {'A', 'C', 'G', 'T'};
private final static int MIN_RANGE = 0;
private final static int MAX_RANGE = 1000;
private final static String INVALID_CHAR = "Invalid input,not matched
with dataset";
private final static String CHAR_LENGTH_EXCEEDS = "Input does not
allow to be exceeds more than " + MAX_RANGE + " characters";
private static String returnFinalComplement(String reverseStr) {
//APPROACH-1
StringBuilder finalStr = new StringBuilder();
for (char c : reverseStr.toCharArray()) {
finalStr.append(
c == 'G' ? 'C'
: c == 'C' ? 'G'
: c == 'T' ? 'A'
: c == 'A' ? 'T'
: c
);
}
return finalStr.toString();
//APPROACH-2
char[] charlist = list.toCharArray();
for (int i = 0; i < charlist.length; i++) {
switch (charlist[i]) {
case 'A': {
charlist[i] = 'T';
}
break;
case 'T': {
charlist[i] = 'A';
}
break;
case 'G': {
charlist[i] = 'C';
}
break;
case 'C': {
charlist[i] = 'G';
}
break;
}
}
return new String(charlist);
}
public static boolean validateInput(String input) {
List<Character> chars = new ArrayList<>();
for (char c : input.toCharArray()) {
chars.add(c);
}
boolean result = false;
SortedSet<Character> mySet = new TreeSet<>(chars);
for (int i = 0; i <= mySet.size();) {
for (Character c : mySet) {
result = Objects.equals(c, DATASET[i]);
i++;
if (!result) {
break;
}
}
if (result) {
return result;
} else {
break;
}
}
return result;
}
public static String reverseIt(String source) {
int i, len = source.length();
StringBuilder dest = new StringBuilder(len);
for (i = (len - 1); i >= 0; i--) {
dest.append(source.charAt(i));
}
return dest.toString();
}
public static void main(String[] args) throws IOException {
BufferedReader readInput = new BufferedReader(new
InputStreamReader(System.in));
String source = readInput.readLine();
if (source.length() > MIN_RANGE && source.length() <= MAX_RANGE) {
boolean validateInput = validateInput(source);
if (validateInput) {
// String reverseString = reverseIt(source);
String reverseString = reverseIt(source);
System.out.println(returnFinalComplement(reverseString));
// String revereStringComplement =
returnFinalComplement(reverseString);
} else {
System.out.println(INVALID_CHAR);
}
} else {
System.out.println(CHAR_LENGTH_EXCEEDS);
}
}
}

Find the first non repeating character in a string

I m writing a method to find the first non repeating character in a string. I saw this method in a previous stackoverflow question
public static char findFirstNonRepChar(String input){
char currentChar = '\0';
int len = input.length();
for(int i=0;i<len;i++){
currentChar = input.charAt(i);
if((i!=0) && (currentChar!=input.charAt(i-1)) && (i==input.lastIndexOf(currentChar))){
return currentChar;
}
}
return currentChar;
}
I came up with a solution using a hashtable where I have two for loops (not nested) where I interate through the string in one loop writing down each occurance of a letter (for example in apple, a would have 1, p would have 2, etc.) then in the second loop I interate through the hashtable to see which one has a count of 1 first. What is the benefit to the above method over what I came up with? I am new to Java does having two loops (not nested) hinder time complexity. Both these algorithms should have O(n) right? Is there another faster, less space complexity algorithm for this question than these two solutions?
public class FirstNonRepeatCharFromString {
public static void main(String[] args) {
String s = "java";
for(Character ch:s.toCharArray()) {
if(s.indexOf(ch) == s.lastIndexOf(ch)) {
System.out.println("First non repeat character = " + ch);
break;
}
}
}
}
As you asked if your code is from O(n) or not, I think it's not, because in the for loop, you are calling lastIndexOf and it's worst case is O(n). So it is from O(n^2).
About your second question: having two loops which are not nested, also makes it from O(n).
If assuming non unicode characters in your input String, and Uppercase or Lowercase characters are assumed to be different, the following would do it with o(n) and supports all ASCII codes from 0 to 255:
public static Character getFirstNotRepeatedChar(String input) {
byte[] flags = new byte[256]; //all is initialized by 0
for (int i = 0; i < input.length(); i++) { // O(n)
flags[(int)input.charAt(i)]++ ;
}
for (int i = 0; i < input.length(); i++) { // O(n)
if(flags[(int)input.charAt(i)] > 0)
return input.charAt(i);
}
return null;
}
Thanks to Konstantinos Chalkias hint about the overflow, if your input string has more than 127 occurrence of a certain character, you can change the type of flags array from byte[] to int[] or long[] to prevent the overflow of byte type.
Hope it would be helpful.
The algorithm you showed is slow: it looks for each character in the string, it basically means that for each character you spend your time checking the string twice!! Huge time loss.
The best naive O(n) solution basically holds all the characters in order of insertion (so the first can be found) and maps a mutable integer to them. When we're done, analyzing, we go through all the entries and return the first character that was registered and has a count of 1.
There are no restrictions on the characters you can use. And AtomicInteger is available with import java.util.concurrent.atomic.AtomicInteger.
Using Java 8:
public static char findFirstNonRepChar(String string) {
Map<Integer,Long> characters = string.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
return (char)(int)characters.entrySet().stream()
.filter(e -> e.getValue() == 1L)
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() -> new RuntimeException("No unrepeated character"));
}
Non Java 8 equivalent:
public static char findFirstNonRepChar(String string) {
Map<Character, AtomicInteger> characters = new LinkedHashMap<>(); // preserves order of insertion.
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
AtomicInteger n = characters.get(c);
if (n == null) {
n = new AtomicInteger(0);
characters.put(c, n);
}
n.incrementAndGet();
}
for (Map.Entry<Character, AtomicInteger> entry: characters.entries()) {
if (entry.getValue().get() == 1) {
return entry.getKey();
}
}
throw new RuntimeException("No unrepeated character");
}
import java.util.LinkedHashMap;
import java.util.Map;
public class getFirstNonRep {
public static char get(String s) throws Exception {
if (s.length() == 0) {
System.out.println("Fail");
System.exit(0);
} else {
Map<Character, Integer> m = new LinkedHashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
if (m.containsKey(s.charAt(i))) {
m.put(s.charAt(i), m.get(s.charAt(i)) + 1);
} else {
m.put(s.charAt(i), 1);
}
}
for (Map.Entry<Character, Integer> hm : m.entrySet()) {
if (hm.getValue() == 1) {
return hm.getKey();
}
}
}
return 0;
}
public static void main(String[] args) throws Exception {
System.out.print(get("Youssef Zaky"));
}
}
This solution takes less space and less time, since we iterate the string only one time.
Works for any type of characters.
String charHolder; // Holds
String testString = "8uiuiti080t8xt8t";
char testChar = ' ';
int count = 0;
for (int i=0; i <= testString.length()-1; i++) {
testChar = testString.charAt(i);
for (int j=0; j < testString.length()-1; j++) {
if (testChar == testString.charAt(j)) {
count++;
}
}
if (count == 1) { break; };
count = 0;
}
System.out.println("The first not repeating character is " + testChar);
I accumulated all possible methods with string length 25'500 symbols:
private static String getFirstUniqueChar(String line) {
String result1 = null, result2 = null, result3 = null, result4 = null, result5 = null;
int length = line.length();
long start = System.currentTimeMillis();
Map<Character, Integer> chars = new LinkedHashMap<Character, Integer>();
char[] charArray1 = line.toCharArray();
for (int i = 0; i < length; i++) {
char currentChar = charArray1[i];
chars.put(currentChar, chars.containsKey(currentChar) ? chars.get(currentChar) + 1 : 1);
}
for (Map.Entry<Character, Integer> entry : chars.entrySet()) {
if (entry.getValue() == 1) {
result1 = entry.getKey().toString();
break;
}
}
long end = System.currentTimeMillis();
System.out.println("1st test:\n result: " + result1 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
String current = Character.toString(line.charAt(i));
String left = line.substring(0, i);
if (!left.contains(current)) {
String right = line.substring(i + 1);
if (!right.contains(current)) {
result2 = current;
break;
}
}
}
end = System.currentTimeMillis();
System.out.println("2nd test:\n result: " + result2 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
char currentChar = line.charAt(i);
if (line.indexOf(currentChar) == line.lastIndexOf(currentChar)) {
result3 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("3rd test:\n result: " + result3 + "\n time: " + (end - start));
start = System.currentTimeMillis();
char[] charArray4 = line.toCharArray();
for (int i = 0; i < length; i++) {
char currentChar = charArray4[i];
int count = 0;
for (int j = 0; j < length; j++) {
if (currentChar == charArray4[j] && i != j) {
count++;
break;
}
}
if (count == 0) {
result4 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("4th test:\n result: " + result4 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
char currentChar = line.charAt(i);
int count = 0;
for (int j = 0; j < length; j++) {
if (currentChar == line.charAt(j) && i != j) {
count++;
break;
}
}
if (count == 0) {
result5 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("5th test:\n result: " + result5 + "\n time: " + (end - start));
return result1;
}
And time results (5 times):
1st test:
result: g
time: 13, 12, 12, 12, 14
2nd test:
result: g
time: 55, 56, 59, 70, 59
3rd test:
result: g
time: 2, 3, 2, 2, 3
4th test:
result: g
time: 3, 3, 2, 3, 3
5th test:
result: g
time: 6, 5, 5, 5, 6
public static char NonReapitingCharacter(String str) {
Set<Character> s = new HashSet();
char ch = '\u0000';
for (char c : str.toCharArray()) {
if (s.add(c)) {
if (c == ch) {
break;
} else {
ch = c;
}
}
}
return ch;
}
Okay I misread the question initially so here's a new solution. I believe is this O(n). The contains(Object) of HashSet is O(1), so we can take advantage of that and avoid a second loop. Essentially if we've never seen a specific char before, we add it to the validChars as a potential candidate to be returned. The second we see it again however, we add it to the trash can of invalidChars. This prevents that char from being added again. At the end of the loop (you have to loop at least once no matter what you do), you'll have a validChars hashset with n amount of elements. If none are there, then it will return null from the Character class. This has a distinct advantage as the char class has no good way to return a 'bad' result so to speak.
public static Character findNonRepeatingChar(String x)
{
HashSet<Character> validChars = new HashSet<>();
HashSet<Character> invalidChars = new HashSet<>();
char[] array = x.toCharArray();
for (char c : array)
{
if (validChars.contains(c))
{
validChars.remove(c);
invalidChars.add(c);
}
else if (!validChars.contains(c) && !invalidChars.contains(c))
{
validChars.add(c);
}
}
return (!validChars.isEmpty() ? validChars.iterator().next() : null);
}
If you are only interested for characters in the range a-z (lowercase as OP requested in comments), you can use this method that requires a minimum extra storage of two bits per character Vs a HashMap approach.
/*
* It works for lowercase a-z
* you can scale it to add more characters
* eg use 128 Vs 26 for ASCII or 256 for extended ASCII
*/
public static char getFirstNotRepeatedChar(String input) {
boolean[] charsExist = new boolean[26];
boolean[] charsNonUnique = new boolean[26];
for (int i = 0; i < input.length(); i++) {
int index = 'z' - input.charAt(i);
if (!charsExist[index]) {
charsExist[index] = true;
} else {
charsNonUnique[index] = true;
}
}
for (int i = 0; i < input.length(); i++) {
if (!charsNonUnique['z' - input.charAt(i)])
return input.charAt(i);
}
return '?'; //example return of no character found
}
In case of two loops (not nested) the time complexity would be O(n).
The second solution mentioned in the question can be implemented as:
We can use string characters as keys to a map and maintain their count. Following is the algorithm.
1.Scan the string from left to right and construct the count map.
2.Again, scan the string from left to right and check for count of each character from the map, if you find an element who’s count is 1, return it.
package com.java.teasers.samples;
import java.util.Map;
import java.util.HashMap;
public class NonRepeatCharacter {
public static void main(String[] args) {
String yourString = "Hi this is javateasers";//change it with your string
Map<Character, Integer> characterMap = new HashMap<Character, Integer>();
//Step 1 of the Algorithm
for (int i = 0; i < yourString.length(); i++) {
Character character = yourString.charAt(i);
//check if character is already present
if(null != characterMap.get(character)){
//in case it is already there increment the count by 1.
characterMap.put(character, characterMap.get(character) + 1);
}
//in case it is for the first time. Put 1 to the count
else
characterMap.put(character, 1);
}
//Step 2 of the Algorithm
for (int i = 0; i < yourString.length(); i++) {
Character character = yourString.charAt(i);
int count = characterMap.get(character);
if(count == 1){
System.out.println("character is:" + character);
break;
}
}
}
}
public char firstNonRepeatedChar(String input) {
char out = 0;
int length = input.length();
for (int i = 0; i < length; i++) {
String sub1 = input.substring(0, i);
String sub2 = input.substring(i + 1);
if (!(sub1.contains(input.charAt(i) + "") || sub2.contains(input
.charAt(i) + ""))) {
out = input.charAt(i);
break;
}
}
return out;
}
Since LinkedHashMap keeps the order of insertion
package com.company;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] argh) {
Scanner sc = new Scanner(System.in);
String l = sc.nextLine();
System.out.println(firstCharNoRepeated(l));
}
private static String firstCharNoRepeated(String l) {
Map<String, Integer> chars = new LinkedHashMap();
for(int i=0; i < l.length(); i++) {
String c = String.valueOf(l.charAt(i));
if(!chars.containsKey(c)){
chars.put(c, i);
} else {
chars.remove(c);
}
}
return chars.keySet().iterator().next();
}
}
Few lines of code, works for me.
public class FirstNonRepeatingCharacter {
final static String string = "cascade";
public static void main(String[] args) {
char[] charArr = string.toCharArray();
for (int i = 0; charArr.length > i; i++) {
int count = 0;
for (int j = 0; charArr.length > j; j++) {
if (charArr[i] == charArr[j]) {
count++;
}
}
if (count == 1){
System.out.println("First Non Repeating Character is: " + charArr[i]);
break;
}
}
}
}
Constraint for this solution:
O(n) time complexity. My solution is O(2n), follow Time Complexity analysis,O(2n) => O(n)
import java.util.HashMap;
public class FindFirstNonDuplicateCharacter {
public static void main(String args[]) {
System.out.println(findFirstNonDuplicateCharacter("abacbcefd"));
}
private static char findFirstNonDuplicateCharacter(String s) {
HashMap<Character, Integer> chDupCount = new HashMap<Character, Integer>();
char[] charArr = s.toCharArray();
for (char ch: charArr) { //first loop, make the tables and counted duplication by key O(n)
if (!chDupCount.containsKey(ch)) {
chDupCount.put(ch,1);
continue;
}
int dupCount = chDupCount.get(ch)+1;
chDupCount.replace(ch, dupCount);
}
char res = '-';
for(char ch: charArr) { //second loop, get the first duplicate by count number, O(2n)
// System.out.println("key: " + ch+", value: " + chDupCount.get(ch));
if (chDupCount.get(ch) == 1) {
res = ch;
break;
}
}
return res;
}
}
Hope it help
char firstNotRepeatingCharacter(String s) {
for(int i=0; i< s.length(); i++){
if(i == s.lastIndexOf(s.charAt(i)) && i == s.indexOf(s.charAt(i))){
return s.charAt(i);
}
}
return '_';
}
String a = "sampapl";
char ar[] = a.toCharArray();
int dya[] = new int[256];
for (int i = 0; i < dya.length; i++) {
dya[i] = -1;
}
for (int i = 0; i < ar.length; i++) {
if (dya[ar[i]] != -1) {
System.out.println(ar[i]);
break;
} else {
dya[ar[i]] = ar[i];
}
}
This is solution in python:
input_str = "interesting"
#input_str = "aabbcc"
#input_str = "aaaapaabbcccq"
def firstNonRepeating(param):
counts = {}
for i in range(0, len(param)):
# Store count and index repectively
if param[i] in counts:
counts[param[i]][0] += 1
else:
counts[param[i]] = [1, i]
result_index = len(param) - 1
for x in counts:
if counts[x][0] == 1 and result_index > counts[x][1]:
result_index = counts[x][1]
return result_index
result_index = firstNonRepeating(input_str)
if result_index == len(input_str)-1:
print("no such character found")
else:
print("first non repeating charater found: " + input_str[result_index])
Output:
first non repeating charater found: r
import java.util.*;
public class Main {
public static void main(String[] args) {
String str1 = "gibblegabbler";
System.out.println("The given string is: " + str1);
for (int i = 0; i < str1.length(); i++) {
boolean unique = true;
for (int j = 0; j < str1.length(); j++) {
if (i != j && str1.charAt(i) == str1.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("The first non repeated character in String is: " + str1.charAt(i));
break;
}
}
}
}
public class GFG {
public static void main(String[] args) {
String s = "mmjjjjmmn";
for (char c : s.toCharArray()) {
if (s.indexOf(c) == s.lastIndexOf(c)) {
System.out.println("First non repeated is:" + c);
break;
}
}
}
output = n
Non Repeated Character String in Java
public class NonRepeatedCharacter {
public static void main(String[] args) {
String s = "ffeeddbbaaclck";
for (int i = 0; i < s.length(); i++) {
boolean unique = true;
for (int j = 0; j < s.length(); j++) {
if (i != j && s.charAt(i) == s.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("First non repeated characted in String \""
+ s + "\" is:" + s.charAt(i));
break;
}
}
}
}
Output:
First non repeated characted in String "ffeeddbbaaclck" is:l
For More Details
In this coding i use length of string to find the first non repeating letter.
package com.string.assingment3;
import java.util.Scanner;
public class FirstNonRepetedChar {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter a String : ");
String str = in.next();
char[] ch = str.toCharArray();
int length = ch.length;
int x = length;
for(int i=0;i<length;i++) {
x = length-i;
for(int j=i+1;j<length;j++) {
if(ch[i]!=ch[j]) {
x--;
}//if
}//inner for
if(x==1) {
System.out.println(ch[i]);
break;
}
else {
continue;
}
}//outer for
}
}// develope by NDM
In Kotlin
fun firstNonRepeating(string: String): Char?{
//Get a copy of the string
var copy = string
//Slice string into chars then convert them to string
string.map { it.toString() }.forEach {
//Replace first occurrance of that character and check if it still has it
if (copy.replaceFirst(it,"").contains(it))
//If it has the given character remove it
copy = copy.replace(it,"")
}
//Return null if there is no non-repeating character
if (copy.isEmpty())
return null
//Get the first character from what left of that string
return copy.first()
}
https://pl.kotl.in/KzL-veYNZ
public static void firstNonRepeatFirstChar(String str) {
System.out.println("The given string is: " + str);
for (int i = 0; i < str.length(); i++) {
boolean unique = true;
for (int j = 0; j < str.length(); j++) {
if (i != j && str.charAt(i) == str.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("The first non repeated character in String is: " + str.charAt(i));
break;
}
}
}
Using Set with single for loop
public static Character firstNonRepeatedCharacter(String str) {
Character result = null;
if (str != null) {
Set<Character> set = new HashSet<>();
for (char c : str.toCharArray()) {
if (set.add(c) && result == null) {
result = c;
} else if (result != null && c == result) {
result = null;
}
}
}
return result;
}
You can achieve this in single traversal of String using LinkedHashSet as follows:
public static Character getFirstNonRepeatingCharacter(String str) {
Set<Character> result = new LinkedHashSet<>(256);
for (int i = 0; i< str.length(); ++i) {
if(!result.add(str.charAt(i))) {
result.remove(str.charAt(i));
}
}
if(result.iterator().hasNext()) {
return result.iterator().next();
}
return null;
}
For Java;
char firstNotRepeatingCharacter(String s) {
HashSet<String> hs = new HashSet<>();
StringBuilder sb =new StringBuilder(s);
for (int i = 0; i<s.length(); i++){
char c = sb.charAt(i);
if(s.indexOf(c) == i && s.indexOf(c, i+1) == -1 ) {
return c;
}
}
return '_';
}
public class FirstNonRepeatingChar {
public static void main(String[] args) {
String s = "hello world i am here";
s.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
.entrySet().stream().filter(e -> e.getValue() == 1).findFirst().ifPresent(e->System.out.println(e.getKey()));
}
}
package looping.concepts;
import java.util.Scanner;
public class Line {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter name: ");
String a = sc.nextLine();
int i = 0;
int j = 0;
for (i = 0; i < a.length(); i++) {
char ch = a.charAt(i);
int counter = 0;
// boolean repeat = false;
for (j = 0; j < a.length(); j++) {
if (ch == a.charAt(j)) {
counter++;
}
}
if (counter == 1) {
System.out.print(ch);
}
else
{
System.out.print("There is no non repeated character");
break;
}
}
}
}
import java.util.Scanner;
public class NonRepaeated1
{
public static void main(String args[])
{
String str;
char non_repeat=0;
int len,i,j,count=0;
Scanner s = new Scanner(System.in);
str = s.nextLine();
len = str.length();
for(i=0;i<len;i++)
{
non_repeat=str.charAt(i);
count=1;
for(j=0;j<len;j++)
{
if(i!=j)
{
if(str.charAt(i) == str.charAt(j))
{
count=0;
break;
}
}
}
if(count==1)
break;
}
if(count == 1)
System.out.print("The non repeated character is : " + non_repeat);
}
}
package com.test.util;
public class StringNoRepeat {
public static void main(String args[]) {
String st = "234123nljnsdfsdf41l";
String strOrig=st;
int i=0;
int j=0;
String st1="";
Character ch=' ';
boolean fnd=false;
for (i=0;i<strOrig.length(); i++) {
ch=strOrig.charAt(i);
st1 = ch.toString();
if (i==0)
st = strOrig.substring(1,strOrig.length());
else if (i == strOrig.length()-1)
st=strOrig.substring(0, strOrig.length()-1);
else
st=strOrig.substring(0, i)+strOrig.substring(i+1,strOrig.length());
if (st.indexOf(st1) == -1) {
fnd=true;
j=i;
break;
}
}
if (!fnd)
System.out.println("The first no non repeated character");
else
System.out.println("The first non repeated character is " +strOrig.charAt(j));
}
}

How do I reverse the order of only the digits in a string?

Given a string in Java, how can I obtain a new string where all adjacent sequences of digits are reversed?
My code:
import static java.lang.System.*;
public class P2
{
public static void main(String[] args)
{
if(args.length < 1)
{
err.printf("Usage: java -ea P2 String [...]\n");
exit(1);
}
String[] norm = new String[args.length];
for(int i = 0; i<norm.length;i++)
{
norm[i] = args[i];
}
}
public String invertDigits(String[] norm)
{
}
}
And as an example, this is what it should do:
Inputs: 1234 abc9876cba a123 312asd a12b34c56d
1234 -> 4321
abc9876cba -> abc6789cba
a123 -> a321
312asd -> 213asd
a12b34c56d -> a21b43c65d
Although the question is heavily downvoted, the proposed problem seems clear now. I chose to solve it using a regular expression match in a recursive function.
private static String reverseDigits(String s) {
// the pattern will match a sequence of 1 or more digits
Matcher matcher = Pattern.compile("\\d+").matcher(s);
// fetch the position of the next sequence of digits
if (!matcher.find()) {
return s; // no more digits
}
// keep everything before the number
String pre = s.substring(0, matcher.start());
// take the number and reverse it
String number = matcher.group();
number = new StringBuilder(number).reverse().toString();
// continue with the rest of the string, then concat!
return pre + number + reverseDigits(s.substring(matcher.end()));
}
And here's the iterative approach.
private static String reverseDigits(String s) {
//if (s.isEmpty()) return s;
String res = "";
int base = 0;
Matcher matcher = Pattern.compile("\\d+").matcher(s);
while (!matcher.hitEnd()) {
if (!matcher.find()) {
return res + s.substring(base);
}
String pre = s.substring(base, matcher.start());
base = matcher.end();
String number = matcher.group();
number = new StringBuilder(number).reverse().toString();
res += pre + number;
}
return res;
}
String str = "1234";
//indexes
int i = 0, j = str.length()-1;
// find digits (if any)
while (!Character.isDigit(str.charAt(i)) && i < str.length()) {
i++;
}
while (!Character.isDigit(str.charAt(j)) && j >= 0) {
j--;
}
// while we havent searched all the digits
while (i < j) {
// switch digits
str = str.substring(0, i) + str.charAt(j) + str.substring(i + 1, j) + str.charAt(i) + str.substring(j + 1);
i++;
j--;
// find the next digits
while (!Character.isDigit(str.charAt(i)) && i < str.length()) {
i++;
}
while (!Character.isDigit(str.charAt(j)) && j >= 0) {
j--;
}
}
System.out.println(str);
Another dynamic approach without using regex classes:
public static String reverseOnlyNumbers(String s) {
StringBuilder digits = new StringBuilder();
StringBuilder result = new StringBuilder();
boolean start = false;
for (int i = 0; i < s.length(); i++) {
Character c = s.charAt(i);
if (Character.isDigit(c)) {
start = true;
digits.append(c);
}else {
start = false;
if (digits.length() > 0) {
result.append(digits.reverse().toString());
digits = new StringBuilder();
}
result.append(c);
}
}
return start ? result.append(digits.reverse()).toString() : result.toString();
}

Java calculator crashing with input of parentheses

Help me stackoverflow, you're my only hope. I have been trying to make a simple calculator, and finally I've gotten it to WORK! The problem is that only simply expressions are evaluated. For example: 4*5 would give 20.0. (Awesome!)
Whenever I give it a more complicated expression like 4*(2+3), the program crashes due to an EmptyStackException. I understand the exception, but I am unable to recreate the problem in my mind when I run through the code manually with my brain and a sheet of paper.
Can anyone figure out why it's crashing? Here is the full code. I marked where the code crashes with some bold, all-caps words. (i.e. PROGRAM CRASHES HERE)
/**
* Human
* Project 3: SUPER-DUPER JAVA CALCULATOR
*/
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator {
public static class SyntaxErrorException extends Exception {
/**
* Construct a SyntaxErrorException with the specified message.
*
* #param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/**
* This is the stack of operands:
* i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/**
* This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/**
* These are the possible operators
*/
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/**
* This is an ArrayList of all the discrete
* things (operators/operands) making up an input.
* This is really just getting rid of the spaces,
* and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix) {
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length() - 1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length() - 1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c) != -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(":
numLP++;
break;
case "[":
numLB++;
break;
case "{":
numLBr++;
break;
case ")":
numRP++;
break;
case "]":
numRB++;
break;
case "}":
numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(":
doop++;
break;
case "[":
scoop++;
break;
case "{":
foop++;
break;
case ")":
doop--;
break;
case "]":
scoop--;
break;
case "}":
foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size() - 1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**
* Method to process operators
*
* #param op The operator
* #throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op == "(" || op == "[" || op == "{") {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
operatorStack.push(op);
} else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp == "(" || topOp == "[" || topOp == "{") {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if (op != ")" || op != "]" || op != "}") {
operatorStack.push(op);
}
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default:
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
do {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (EmptyStackException e) {
System.out.println("Make sure you only put in operators and operands.");
}
} while (true);
}
}
Stack trace:
java.util.EmptyStackException at
java.util.Stack.peek(Stack.java:102) at
java.util.Stack.pop(Stack.java:84) at
InfixEvaluator.processOperator(InfixEvaluator.java:177) at
InfixEvaluator.infixCalculator(InfixEvaluator.java:225) at
InfixEvaluator.main(InfixEvaluator.java:276)
Your error comes from poping an element off the stack when the stack is empty. Hence the name EmptyStackException.
I noticed in your loops you say something like while(!operatorStack.empty()) but then inside the while loop you pop 2 or sometimes 3 elements off the stack. If you want to pop more elements off an array than one you should test for that in your while loop.
So if you pop 2 elements off then do while (operatorStack.size() > 2 ). I edited your code changing all your while loops to be correct and it worked fine for these inputs
(2+3)
and
(2+3)+5
Here is what I did:
Moved boilerplate code into new methods
Added method signatures comments
Fixed your operator precedence, pow operator had the wrong precedence.
Changed String comparison in a bunch of places from str1 == str2 to str1.equals(str2). You should look at How do I compare strings in Java? to see why I did that.
Added in System.out.println statements to debug your application. I left them in so you can see the output and check it for yourself. You should look through and see what I did to help you debug in the future.
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator
{
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
#param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
// + - / * % ^ ( ) [ ] { }
private static final int[] PRECEDENCE = {1, 1, 2, 2, 3, 3, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
/**
* TODO: write this
* #param postfix
* #return
*/
public static ArrayList inputCleaner(String postfix){
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length()-1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
switch (input.get(f)) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* #param op The operator
* #throws SyntaxErrorException
* #throws EmptyStackException
*/
private static void processOperator(String op) throws SyntaxErrorException {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
topOp = op;
operatorStack.push(op);
} else {
System.out.println(operatorStack);
System.out.println(operandStack);
System.out.println("--------------");
//Pop all stacked operators with equal
// or higher precedence than op.
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
if(op.equals("(") || op.equals("[") || op.equals("{")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if(!op.equals(")") || !op.equals("}") || !op.equals("}")) {
operatorStack.push(op);
}
}
}
}
/**
* TODO: write this
* #param expressions
* #return
* #throws SyntaxErrorException
*/
public static String infixCalculator(ArrayList<String> expressions) throws SyntaxErrorException {
for (String expression : expressions) {
if (OPERATORS.indexOf(expression) == -1) {
operandStack.push(Double.parseDouble(expression));
} else {
processOperator(expression);
}
}
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
System.out.println("--------------");
System.out.println(operandStack);
System.out.println(operatorStack);
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
}
if(operandStack.isEmpty())
return null;
return String.valueOf(operandStack.pop());
}
/**
* goes through the stack and pops off all non operatable operations until it gets to one that is in the NONBRACES String
* #return The next operatable string
*/
private static String getNextNonBracerOperator() {
String work = "\0"; // \0 is null,
while(!operatorStack.isEmpty() && NONBRACES.indexOf(work) == -1)
work = operatorStack.pop();
return work;
}
/**
*
* #param work The operator you want to work. This really should be a character but its still a string
* #param l Left side number
* #param r Right side number
* #throws SyntaxErrorException If the operator could not be found
*/
private static void doOperandWork(String work, double l, double r) throws SyntaxErrorException {
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default:
throw new SyntaxErrorException("Invalid operand " + work);
}
}
/**
* #param op The operator
* #return the precedence
*/
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
//System.out.println("Please insert an argument: ");
//String g = f.nextLine();
//String g = "(1+1)^(3+1)";
String g = "(1+3)*3^2+2*4-1";
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (SyntaxErrorException e) {
System.out.println("Make sure you only put in operators and operands.");
e.printStackTrace();
}
}
}
You are trying to compare a String with ==. Instead use String.equals(String)
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
...
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
...
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
If you then trace through you code, you will see that you are trying to use "(" as an operator
You have already pushed ")" back onto the stack before you check. You should move the check up.
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
Final Code
import java.util.*;
public class InfixEvaluator
{
public static void main(String[] args) {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
}
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
#param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix){
StringBuilder poop = new StringBuilder();
String doody = postfix.replace(" ", "");
try {
for (int i = 0; i < doody.length(); i++) {
char c = doody.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
poop.append(c);
if (i == doody.length()-1) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
} else if (c == '.') {
for (int j = 0; j < poop.length(); j++) {
if (poop.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == poop.length() - 1) {
poop.append(c);
j = (poop.length() + 1);
}
}
if (poop.length() == 0) {
poop.append(c);
}
if (i == doody.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (poop.length() != 0) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
poop.append(c);
input.add(poop.toString());
poop.delete(0, poop.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* #param op The operator
* #throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop(); //***THE PROGRAM CRASHES HERE***
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
}

Categories