i am confused on why it doest not split the string? my array of string exp does not contain anything when i debug it is the split wrong?what i am trying to do is to split a very simple expression like 1+2+3 and then parse the values, doing a calculator.
EDIT
hi, why i am splitting on each character is because i am doing a calculator, and have read something about converting infix to postfix,so i need to split the string and then loop through each of the string and do the checking as shown below,however when i debug it shows the exp[] is empty
For each token in turn in the input infix expression:
* If the token is an operand, append it to the postfix output.
* If the token is an operator A then:
o While there is an operator B of higher or equal precidence than A at the top of the stack, pop B off the stack and append it to the output.
o Push A onto the stack.
* If the token is an opening bracket, then push it onto the stack.
* If the token is a closing bracket:
o Pop operators off the stack and append them to the output, until the operator at the top of the stack is a opening bracket.
o Pop the opening bracket off the stack.
When all the tokens have been read:
* While there are still operator tokens in the stack:
o Pop the operator on the top of the stack, and append it to the output.
// the main class
public class Main {
public static void main(String[] args) {
calcExpChecker calc = new calcExpChecker("1+2+3+4");
calc.legitExp();
calc.displayPostfix();
}
}
//the class
package javaapplication4;
import java.util.*;
public class calcExpChecker {
private String originalExp; // the orginal display passed
private boolean isItLegitExp; // the whole expression is it legit
private boolean isItBlank; // is the display blank?
private StringBuilder expression = new StringBuilder(50);
private Stack stack = new Stack();//stack for making a postfix string
calcExpChecker(String original)
{
originalExp = original;
}
//check for blank expression
public void isitBlank()
{
if(originalExp.equals(""))
{
isItBlank = true;
}
else
{
isItBlank = false;
}
}
//check for extra operators
public void legitExp()
{
String[] exp = originalExp.split(".");
for(int i = 0 ; i < exp.length ; i++)
{
if(exp[i].matches("[0-9]"))
{
expression.append(exp[i]);
}
else if(exp[i].matches("[+]"))
{
if(stack.empty())
{
stack.push(exp[i]);
}
else
{
while(stack.peek().equals("+"))
{
expression.append(stack.pop());
}
stack.push(exp[i]);
}
}
if (!stack.empty())
{
expression.append(stack.pop());
}
}
}
public void displayPostfix()
{
System.out.print(expression.toString());
}
}
If you make every character a delimiter, what is between them? Nothing
e.g.,
1+2+3+4
is 1 a delimiter? yes, ok, capture everything between it and the next delimiter. Next delimiter? +. Nothing captured. Next delimiter? 2. etc etc
You want to split on every character, so rather use string.split("").
for (String part : string.split("")) {
// ...
}
Or better, just iterate over every character returned by string.toCharArray().
for (char c : string.toCharArray()) {
// ...
}
With chars you can use a switch statement which is better than a large if/else block.
why do you need to split on each character & rather not go for foreach character in the String. That way you don't have to reference as exp[i] either.
Anyways you can split using "" instead of "."
Confession:
Okay I guess my answer is bad because there are subtle differences between Java and C# with this stuff. Still, maybe it'll help someone with the same problem but in C#!
Btw, in C#, if you pass in a RegEx "." you don't get an empty array, instead you get an array of blanks (""), one for each character boundary in the string.
Edit
You can pass a regex expression into the split() function:
string expressions = "10+20*4/2";
/* this will separate the string into an array of numbers and the operators;
the numbers will be together rather than split into individual characters
as "" or "." would do;
this should make processing the expression easier
gives you: {"10", "+", "20", "*", "4", "/", "2"} */
foreach (string exp in expressions.split(#"(\u002A)|(\u002B)|(\u002D)|(\u002F)"))
{
//process each number or operator from the array in this loop
}
Original
String[] exp = originalExp.split(".");
You should get at least one string from the return value of split() (the original un-split string). If the array of strings is empty, the original string was probably empty.
Java String Split() Method
Related
I need to create a function in Java translate_string(),
which is doing "translation" of the string letter by letter.
Function takes String as arg, and returns array of String[]:
public static String[] translate_string(String string)
Given existing function translate_letter(),
which takes String as arg and returns array of String[]
public static String[] translate_letter(String letter)
and it translating each letter, I need to sequentially translate
the whole string letter by letter into combination of output strings.
Complexity is, that one character could be translated to multiple
sets of characters, it is not one-to-one relationship between
input string and output string, it is - one-to-many relationship,
where one letter as input could produce multiple combinations
(i.e. arrays) as output.
N.B.: Term translation has nothing to do with actual translation from
one language to another, it is just substitution of one character
to set of other characters.
Below is exact code id simplified version of function
translate_letter() (no modification is required):
//------------------------------------------------------------
// translate letters - return array of diff combinations
public static String[] translate_letter(String s) {
ArrayList<String> o = new ArrayList<>(1);
if ( s.equals("a") ) { // if a
o.add("a1");
} else {
if ( s.equals("b") ) { // if b
o.add("b1"); o.add("b2");
} else {
if ( s.equals("c") ) { // if c
o.add("c1"); o.add("c2"); o.add("c3");
} else {
if ( s.equals("d") ) { // if d
o.add("d1"); o.add("d2"); o.add("d3"); o.add("d4");
} else {
o.add(s); // s = def add (if nothing above matches)
} // end if d
} // end if c
} // end if b
} // end if a
//Convert ArrayList o to string array[]
String[] array = o.toArray(new String[o.size()]);
return array;
} // end translate_letter()
//------------------------------------------------------------
So, how to translate the string?
Let's have a look at simple version of translate - when
translate_letter() return just string.
So, letter "a" will be translated to "a1", letter "b"
will be translated to "b1", "c" - to "c1".
Input string "a" will be translated as "a1", simple.
Input string "ab" will be translated as "a1b1", simple.
Input string "abc" will be translated as "a1b1c1", simple.
I don't need to create this simple version - it is nothing to do here,
just split the input string and translate each letter by letter.
What I want to write (and I cannot do this) - is complicated version of translate_string(),
when function translate_letter() returns multiple combinations,
i.e. - array of output combinations.
For example (according to the code of translate_letter() above,
letter "a" will be translated to "a1", simple.
But letter "b" will be translated by translate_letter() to 2 combinations:
"b1" and "b2",
and output is String[] array = {"b1", "b2" }
So, string "a" will be translated by translate_string() as array of
just 1 element R[] = { "a1" }
String "ab" will be translated as array of 2 elements
R[] = { "a1b1", "a1b2" }
String "abc" will be translated as:
R[] = { "a1b1c1", "a1b1c2", "a1b1c3", "a1b2c1", "a1b2c2", "a1b2c3" }
String "db" will be translated as:
R[] = { "d1b1", "d2b1", "d3b1", "d4b1", "d1b2", "d2b2", "d3b2", "d4b2" }
This task is more complicated, than it seems initially just by
look at it. I have tried and failed with 2 approaches - simple Arrays[]
and Array[] of ArrayList - cannot loop through two array (with different
indexes) at once and need some external help or ideas - how to accomplish this.
You need a recursive translateString method (according to Java naming conventions named in camel case without any underscore in the name). The algorithm is:
If string is the empty string, return an array of one element, the empty string.
From translateLetter() obtain all possible translations of the first letter.
From a recursive call to translateString() obtain all possible translations of the remainder of the string after the first letter. Or for the shortcut: just call translateString() passing the part of the string that comes after the first character as argument.
In two nested loops concatenate each possible translation of the first letter with each possible translation of the remainder of the string. One of the loops will iterate over the possible translations of the first letter obtained from 2. above. The other loop over the possible translations of the remainder of the string obtained from 3. Add the concatenated strings to an ArrayList<String>.
Convert the list to an array and return it.
This is one of the rare occasions I'll answer homework, though Ole V.V. is right.
When we do the homework, the learning effect is relative, and it is not honest with respect to those wo struggled.
public static String[] translate_string(String s) {
Set<String> translations = new HashSet<>();
if (!s.isEmpty()) {
s.codePoints(cp -> {
String letter = new String(new int[] {cp}, 0, 1);
String[] more = translate_letter(letter);
if (more.length == 0) {
} else if (more.length == 1) {
translations.add(more[0]);
} else {
Set<String> prior_translations = new HashSet<>(translations);
translations.clear();
for (String prior: prior_translations) {
for (String letter: letter_translations) {
translations.add(prior + letter);
}
}
}
});
}
return translations.toArray(new String[0]);
}
The trick is: when having N translations and getting for a next letter L letter translations, the result is N×L translations.
The answer of Ole V.V. explains things better.
There are combination of words like is, is not, does not contain. We have to match these words in a sentence and have to split it.
Intput : if name is tom and age is not 45 or name does not contain tom then let me know.
Expected output:
If name is
tom and age is not
45 or name does not contain
tom then let me know
I tried below code to split and extract but the occurrence of "is" is in "is not" as well which my code is not able to find out:
public static void loadOperators(){
operators.add("is");
operators.add("is not");
operators.add("does not contain");
}
public static void main(String[] args) {
loadOperators();
for(String s : operators){
System.out.println(str.split(s).length - 1);
}
}
Since there could be multiple occurence of a word split wouldn't solve your use case, as in is and is not being different operators for you. You would ideally :
Iterate :
1. Find the index of the 'operator'.
2. Search for the next space _ or word.
3. Then update your string as substring from its index to length-1.
I am not entirely sure about what you try to achieve, but let's give it a shot.
For your case, a simple "workaround" might work just fine:
Sort the operators by their length, descending. This way the "largest match" will get found first. You can define "largest" as either literally the longest string, or preferably the number of words (number of spaces contained), so is a has precedence over contains
You'll need to make sure that no matches overlap though, which can be done by comparing all matches' start and end indices and discarding overlaps by some criteria, like first match wins
This code does what you seem to be wanting to do (or what I guessed you are wanting to do):
public static void main(String[] args) {
List<String> operators = new ArrayList<>();
operators.add("is");
operators.add("is not");
operators.add("does not contain");
String input = "if name is tom and age is not 45 or name does not contain tom then let me know.";
List<String> output = new ArrayList<>();
int lastFoundOperatorsEndIndex = 0; // First start at the beginning of input
for (String operator : operators){
int indexOfOperator = input.indexOf(operator); // Find current operator's position
if (indexOfOperator > -1) { // If operator was found
int thisOperatorsEndIndex = indexOfOperator + operator.length(); // Get length of operator and add it to the index to include operator
output.add(input.substring(lastFoundOperatorsEndIndex, thisOperatorsEndIndex).trim()); // Add operator to output (and remove trailing space)
lastFoundOperatorsEndIndex = thisOperatorsEndIndex; // Update startindex for next operator
}
}
output.add(input.substring(lastFoundOperatorsEndIndex, input.length()).trim()); // Add rest of input as last entry to output
for (String part : output) { // Output to console
System.out.println(part);
}
}
But it is highly dependant on the order of the sentence and the operators. If we're talking about user-input, the task will be much more complicated.
A better method using regular expressions (regExp) would be:
public static void main(String... args) {
// Define inputs
String input1 = "if name is tom and age is not 45 or name does not contain tom then let me know.";
String input2 = "the name is tom and he is 22 years old but the name does not contain jack, but merry is 24 year old.";
// Output split strings
for (String part : split(input1)) {
System.out.println(part.trim());
}
System.out.println();
for (String part : split(input2)) {
System.out.println(part.trim());
}
}
private static String[] split(String input) {
// Define list of operators - 'is not' has to precede 'is'!!
String[] operators = { "\\sis not\\s", "\\sis\\s", "\\sdoes not contain\\s", "\\sdoes contain\\s" };
// Concatenate operators to regExp-String for search
StringBuilder searchString = new StringBuilder();
for (String operator : operators) {
if (searchString.length() > 0) {
searchString.append("|");
}
searchString.append(operator);
}
// Replace all operators by operator+\n and split resulting string at \n-character
return input.replaceAll("(" + searchString.toString() + ")", "$1\n").split("\n");
}
Notice the order of the operators! 'is' has to come after 'is not' or 'is not' will always be split.
You can prevent this by using a negative lookahead for the operator 'is'.
So "\\sis\\s" would become "\\sis(?! not)\\s" (reading like: "is", not followed by a " not").
A minimalist Version (with JDK 1.6+) could look like this:
private static String[] split(String input) {
String[] operators = { "\\sis(?! not)\\s", "\\sis not\\s", "\\sdoes not contain\\s", "\\sdoes contain\\s" };
return input.replaceAll("(" + String.join("|", operators) + ")", "$1\n").split("\n");
}
/** Test if delimiters in the given expression are properly matched. */
public static boolean isMatched(String expression) {
final String opening = "({["; // opening delimiters
final String closing = ")}]"; // respective closing delimiters
Stack<Character> buffer = new LinkedStack<>();
for (char c:expression.toCharArray()) {
if (opening.indexOf(c) != -1) // this is a left delimiter
buffer.push(c);
else if (closing.indexOf(c) != -1) { // this is a right delimiter
if (buffer.isEmpty()) // nothing to match with
return false;
if (closing.indexOf(c) != opening.indexOf(buffer.pop()))
return false; // mismatched delimiter
}
}
return buffer.isEmpty(); // were all opening delimiters matched?
}
Assume a generic stack interface, Stack<E> with unimplemented methods: push( E ), pop(), isEmpty() where E is a generic data type.
And a LinkedArray<E> class implementing all Stacks<E> methods.
'expression' in 'isMatched()' is a mathematical expression with braces as delimiters. Ex- [{(a+b)*(c+d)}]; and
isMatched(String expression) is a method to check whether the expression contains correctly paired braces.
buffer is a stack to store the pushed expression's (now an array of char) members.
I am able to understand the code till the for-each loop.
And the lines after that are eating me.
The indexOf("c") method is used to return the index of first occurence of c in the given string. For example String s=" java";
int i= s.indexOf("a");
would set i = 1
Life is very easy if the expression has values from 0 to 9 but
If expression = 23+52*5 is input by user then I take it in a String named expression.
Now what I want is that a new String or char Array in such a fashion that:
String s or char[] ch = ['23','+','52','*','5']
so that ch[0] or s.charAt(0) gives me 23 and not 2.
To do so I have tried the following and am stuck on what to do next:
for(int i=0;i<expression.length();i++)
{
int operand = 0;
while(i<expression.length() && sol.isOperand(expression.charAt(i))) {
// For a number with more than one digits, as we are scanning
// from left to right.
// Everytime , we get a digit towards right, we can
// multiply current total in operand by 10
// and add the new digit.
operand = (operand*10) + (expression.charAt(i) - '0');
i++;
}
// Finally, you will come out of while loop with i set to a non-numeric
// character or end of string decrement it because it will be
// incremented in increment section of loop once again.
// We do not want to skip the non-numeric character by
// incrementing it twice.
i--;
/**
* I have the desired integer value but how to put it on a string
* or char array to fulfill my needs as stated above.
**/
// help or ideas for code here to get desired output
}
In the while loop the method isOperand(char) is returning a boolean value true if char provided is >=0 or <=9.
You're going to want a String[] when you break the expression apart. Regex lookbehind/lookahead (Java Pattern Reference) allows you to split a String and keep the delimiters. In this case, your delimiters are the operands. You can use a split pattern like this:
public static void main(String[] args) throws Exception {
String expression = "23+52*5";
String[] pieces = expression.split("(?<=\\+|-|\\*|/)|(?=\\+|-|\\*|/)");
System.out.println(Arrays.toString(pieces));
}
Results:
[23, +, 52, *, 5]
One this to consider, is if your expression contains any spaces then you're going to want to remove them before splitting the expression apart. Otherwise, the spaces will be included in the results. To remove the spaces from the expression can be done with String.replaceAll() like this:
expression = expression.replaceAll("\\s+", "");
The "\\s+" is a regular expression pattern that means a whitespace character: [ \t\n\x0B\f\r]. This statement replaces all whitespace characters with an empty space essentially removing them.
String expr = "23+52*5";
String[] operands = expr.split("[^0-9]");
String[] operators = expr.split("[0-9]+");
This breaks it into:
try using a switch case:
//read first character
switch data
if number : what is it ( 0,1,2,3...?)
save the number
if its an operator
save operator
** 2 the switch has 4 cases for operators and 10 for digits **
// read the next character
again switch
if its a number after a number add both chars into a string
if its an operator "close" the number string and convert it into an int
If you will need some code I will gladly help.
Hope the answer is useful.
for i = 1 ; i = string.length
switch :
case 1,2,3,4,5,6,7,8,9,0 (if its a digit)
x(char) = char(i)
case +,-,*,/ (operator)
y(char) = char(i)
x[1] + x[2] +...x[n] = X(string) // build all the digits saves before the operator into 1 string
convert_to_int(X(string))
You can use regex:
\d+
Will grab any instance of one or more consecutive digits.
Hey I am writing a calculator script in Java.
I am currently stuck trying to find out a way to find if any of the characters in a sting are in an ArrayList.
For example:
I have to have the input as a String I pass this string into a method of which has access to an array list with the operators and operands in it. How can I make sure that the string only contains the operands and operators within this array list?
Thanks, Ciaran
Here is the code that I have so far with the input being passed in..
import java.util.*;
public class stringCalculator {
private String[] operators = {"+","-","/","*"};
public stringCalculator(String userinput){
System.out.println(userinput);
public boolean checkInput(){
}
}
}
Here is the new code.
import java.util.*;
public class stringCalculator {
private String userinput;
HashSet<String> op = new HashSet<String>();
public stringCalculator(String userinput){
this.userinput = userinput;
//System.out.println(userinput);
HashSet<String> op = new HashSet<String>();
op.add("+");
op.add("-");
op.add("*");
op.add("/");
this.op = op;
System.out.println(op);
}
public void checkTheInput(){
System.out.println(userinput);
}
public boolean checkInput(){
return op.contains(userinput);
}
}
Edited to meet requirement as per comments
To return true if a string contains only -+/* or digits:
public boolean checkInput(String input) {
return input.matches("[-+/*0-9]+");
}
This uses a regular expression to assert that the string contains only the specified characters. A breakdown of the regex:
[...] is a character class, which lists the characters allowed
+ means "one or more of the preceding expression" (in this case the character class)
Note that the minus sign in a character class is for a range of characters, eg 0-9 means 0123456789. However, when a minus is used either first of last in a character class, it means a literal minus (not a range).
Another note about String.matches() - it must match the whole string to return true. This is different from many other languages, where the similar method/function would return true if part of the string matches.
So, you want to take out the numbers, and then check if the remaining characters are all contained in opereators. Assuming your input String is not too long, I'd suggest you use a HashSet instead of String[] for operators. This way, you can use the [contains(Object)][1] method (which will be O(1) instead of O(n)) for anything that's not a number in your String.
As validation goes, however, you'll still have to check for much more, such as: "4++5/-3", where the operands are valid, but the overall expression isn't.
If you want to calculate expressions such as:
(3+4)*5
(which is in INFIX format). it is not very wise to read the string straightly. you should first convert the input to POSTFIX or Reverse Polish format like:
34+5*
This can be done reading characters one by one and using a stack. In that case you can check the characters on the fly one by one storing operators in a Set or Map.
I would recommend having a look at http://en.wikipedia.org/wiki/Reverse_Polish_notation for POSTFIX format and http://www.softwareandfinance.com/Java/Infix_Postfix_Converter.html
for example conversion code.