splitting strings with operator relative to parentheses [closed] - java

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want the following strings to be split by the (relative to the pairs of parentheses) outer-most operator (in this case: '+'):
1: "((20 + 20) + a)"
2: "(20 + ((20 + 20) + 20))
The results should be like this:
1: "((20 + 20) " and " a)"
2: "(20 " and " ((20 + 20) + 20))"

You can't do this with regex, but you can try something like this:
// locations of top-level operators:
List<Integer> locations = new ArrayList<Integer>();
int level = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
level++;
}
else if (c == ')') {
level--;
}
else if ("+-*/".indexOf(c) >= 0 && level == 1) {
locations.add(i);
}
}
You can then "split" your string with substring() and whatever is in locations.
If you always want to split on the outermost operator (e.g. split on + in (((a + 1)))), then things get a little more tricky, but your overall approach doesn't have to change drastically. One idea that comes to mind is to build a Map<OperatorData, Integer> (where OperatorData is a class containing the operator token (e.g. +) and an int representing how far it's nested) that maps to locations in the string. OperatorData can be Comparable based on the nest level.
OperatorData might look something like this:
class OperatorData implements Comparable<OperatorData> {
private String token;
private int level;
// constructor etc.
#Override
public int compareTo(OperatorData other) {
return Integer.compare(level, other.level);
}
}
You can then go through this map and split on the operators that have the lowest nest level. The approach might look something like this:
// location of top-level operators:
Map<OperatorData, Integer> operators = new HashMap<>();
int level = 0;
int i = 0;
while (i < str.length()) {
char c = str.charAt(i);
if (c == '(') {
level++;
} else if (c == ')') {
level--;
} else if (isOperatorChar(c)) {
final int index = i;
StringBuilder token = new StringBuilder();
token.append(c);
while (isOperatorChar(c = str.charAt(i + 1))) {
token.append(c);
i++;
}
operators.put(new OperatorData(token.toString(), level), index);
}
i++;
}
// find smallest OperatorData in map

Related

Check if string contains number after specific word [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 months ago.
Improve this question
can someone help me with string validation? I tried to find the solution, but none was satisfied.
I have the uri e.g. /dog/cat/house,1/mouse/bird,1/rabbit.
I need to check if after word (with comma) bird, there is a number or not. In my case sometimes i receive uri with number: "bird,1" and sometimes with word: "bird,foo".
Thank you for any suggestions.
As #Federico klez Culloca and #The fourth bird suggested you could use a regular expression (\\bbird,(?:[1-9]|1[0-9]|20)\\b) but some security scans don't like regular expressions. In any case, one another (pure Java) solution would be:
Updated the answer after user added more conditions.
would look for range 1, 2 .. 20 (01, 02 would return false).
public static boolean isNumber() {
// you can parametrize these 2
String input = "/dog/cat/house,1/mouse/bird,10/rabbit.";
String strOfInterest = "/bird,";
boolean isStringEndingInLT20 = false;
int indxOfInterest = input.indexOf("/bird,") + strOfInterest.length();
char c1 = input.charAt(indxOfInterest);
char c2 = input.charAt(indxOfInterest + 1);
int i1 = Character.getNumericValue(input.charAt(indxOfInterest));
if (Character.isDigit(c1) && Character.isDigit(c2)) {
int num = Integer.parseInt("" + c1 + c2);
if ((i1 > 0) && (num >= 1) && (i1 <= 20)) isStringEndingInLT20 = true;
} else if (Character.isDigit(c1)) {
if ((i1 >= 1) && (i1 <= 9)) isStringEndingInLT20 = true;
}
return isStringEndingInLT20;
}
NOTE: I personally hate these verbose solutions and would prefer 1 line REGEX. Try to avoid it and use regex. The only times I avoid regex is when it becomes performance bottleneck and/or causes a security concern.
This is a practical algorithm, you can specify the keyword!
The premise is that the validity of the contains parameter is in line with your description.
keyword, (spaces are allowed)123/
public static void main(String[] args) throws IOException {
String contains = "/dog/cat/house,1/mouse/bird,a/rabbit";
FreeTest f = new FreeTest();
boolean has = f.hasNumber(contains, "bird");
System.out.println(has);
}
/**
* Check if string contains number after specific word
*
* #param contains string contains
* #param key the specific word (without comma)
* #return yes or not
*/
public boolean hasNumber(String contains, String key) {
int commaIndex = contains.indexOf(',', contains.indexOf(key));
int startIndex = commaIndex + 1;
boolean hasNumber = true;
while (true) {
char c = contains.charAt(startIndex++);
if (c == '/') break; // exit
if (c != ' ') {
hasNumber = Character.isDigit(c);
}
}
return hasNumber;
}

String combinations with multi-character replacement (yield return alternative re-write for Java) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
There's another Stack Overflow post that was created for an algorithm related to vehicle registration numbers...
According to the entered license plate (eg. ABC123) and a list of
replacement values (eg 1 replaced by I). I need to get all possibles
combinations.
The answer by #ArturoMenchaca is perfect for C#, but I'd like it in Java, but given that 'yield' is not available I really can't wrap my head around how to convert it.
How would you translate this code to Java?
public static IEnumerable<string> Combinations(string s, Dictionary<char, char> replacements)
{
return Combinations(s, replacements, 0, string.Empty);
}
private static IEnumerable<string> Combinations(string original, Dictionary<char, char> replacements, int index, string current)
{
if (index == original.Length) yield return current;
else
{
foreach (var item in Combinations(original, replacements, index + 1, current + original[index]))
yield return item;
if (replacements.ContainsKey(original[index]))
foreach (var item in Combinations(original, replacements, index + 1, current + replacements[original[index]]))
yield return item;
}
}
You would call then call the method like this..
Dictionary<char, char> dict = new Dictionary<char,char>();
dict['1'] = 'I';
dict['3'] = 'B';
dict['A'] = 'H';
dict['O'] = '0';
dict['0'] = 'O';
var combs = Combinations("ABC123", dict);
Java doesn't have a feature for iterating values using "push" logic, like the C# yield return does.
Java only supports "pull" logic, using Enumeration, Iterator, or Spliterator (what Stream uses).
If you have the memory for it, you could of course "push" all the combinations into an ArrayList, then "pull" values from there. Converting the yield return logic into list.add() calls is easy, so I'll assume you don't want that.
The Java equivalent of IEnumerable is Iterable, so you need an Iterator implementation.
The code below will do that. It is based on my answer to another question, so please read that answer for an explanation of the overall logic, but basically, your example would be like generating combinations of characters in this jagged array:
{{'A', 'H'}, {'B'}, {'C'}, {'1', 'I'}, {'2'}, {'3', 'B'}}
In the code below, that jagged array is the textChars array, but instead of using char[] it uses a String, because a String is really just a read-only char[].
public static Iterable<String> combinations(String text, String... replacements) {
Map<Character, String> repl = new HashMap<>();
for (String r : replacements)
if (repl.putIfAbsent(r.charAt(0), r) != null)
throw new IllegalArgumentException("Duplicate replacement: [" + repl.get(r.charAt(0)) + "] vs [" + r + "]");
String[] textChars = new String[text.length()];
long count = 1;
for (int i = 0; i < textChars.length; i++) {
textChars[i] = repl.getOrDefault(text.charAt(i), text.substring(i, i+1));
count = Math.multiplyExact(count, textChars[i].length());
}
long comboCount = count;
return () -> new Iterator<>() {
private long combo = 0;
#Override
public boolean hasNext() {
return (this.combo < comboCount);
}
#Override
public String next() {
if (this.combo >= comboCount)
throw new NoSuchElementException();
long c = this.combo++;
char[] buf = new char[textChars.length];
for (int i = buf.length - 1; i >= 0; i--) {
buf[i] = textChars[i].charAt((int) (c % textChars[i].length()));
c /= textChars[i].length();
}
return new String(buf);
}
};
}
Test
combinations("ABC123", "1I", "3B", "AH", "O0", "0O").forEach(System.out::println);
Output
ABC123
ABC12B
ABCI23
ABCI2B
HBC123
HBC12B
HBCI23
HBCI2B

Expansion of Molecular notation of Chemical Formula [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I looked around a bit for a solution to parsing out a chemical formula that contained molecular components that may have their own suffixes for the purposes of being able to parse a formula for its complete atomic fraction.
How would one do this in Java?
Not having been able to find a way to do this in short order (and not having done a fun algorithm in a while) I settled on a stack implementation, as it's actually less complicated than a math operation stack.
Going backward through the stack, you only have to be aware of a few things, as this is fundamentally a modified implementation of a common solution to parsing a mathematical statement.
1) Your integer suffix can be built of multiple characters
2) Your integer suffix could be a multiplier (next character being a ")")
3) You need to handle for implicit "1"s
The implementation pops characters off one stack and pushes only letters and numbers onto your "return stack".
String expandFormula(String s){
Stack<Character> stack = new Stack();
Stack<Character> hanoi = new Stack();
char[] ca = s.toCharArray();
Character c;
List<Integer> multipliers = new ArrayList();
String multiBuff;
int val;
boolean flag;
for (int i = 0; i < ca.length; i++)
stack.push(ca[i]);
while(!stack.isEmpty()){
c = stack.pop();
if (Character.isLetter(c)){
try{
//previous parse was end of Symbol, implicit "1"
flag = Character.isUpperCase(hanoi.peek());
}
catch(EmptyStackException ese){ //change exception
flag = false;
}
//push implicit 1
if (flag){
stack.push(c);
stack.push('1');
}
//continue as usual
else
hanoi.push(c);
}
//begin number parsing
else if(Character.isDigit(c)){
flag = false;
multiBuff = c +"";
//parse the integer out
while(Character.isDigit(stack.peek())){
c = stack.pop();
multiBuff = c + multiBuff;
}
//if next char is ), then value is a suffix
if (stack.peek() == ')'){
flag = true;
stack.pop();
multipliers.add(Integer.parseInt(multiBuff));
//pop successive )s
while(stack.peek() == ')'){
stack.pop();
multipliers.add(1);
}
}
if(Character.isLetter(stack.peek())){
val = flag ? 0 : Integer.parseInt(multiBuff);
//get full value of
for(Integer i : multipliers){
if (val == 0)
val = i;
else
val *= i;
}
//trim and push first decibit
while(val > 0){
hanoi.push(Character.forDigit(val % 10, 10));
val /= 10;
}
}
}
//end of nest, remove most recent multiplier
else if(c == '(')
try{
multipliers.remove(multipliers.size()-1);
}
catch(ArrayIndexOutOfBoundsException aioobe){
}
}
multiBuff = "";
while(!hanoi.isEmpty())
multiBuff += hanoi.pop();
return multibuff;
}
This solution can be converted directly to your output string by:
1) Change "hanoi" to string
2) Change "hanoi.push(c)" to hanoi = c + hanoi
3) Change "hanoi.peek()" to "hanoi.charAt(0)"
4) Change Exceptions as necessary (or use general exceptions anyway)
5) Just return hanoi instead of the multibuff thing at the bottom.

Returning a string minus a specific character between specific characters

I am going through the Java CodeBat exercises. Here is the one I am stuck on:
Look for patterns like "zip" and "zap" in the string -- length-3, starting with 'z' and ending with 'p'. Return a string where for all such words, the middle letter is gone, so "zipXzap" yields "zpXzp".
Here is my code:
public String zipZap(String str){
String s = ""; //Initialising return string
String diff = " " + str + " "; //Ensuring no out of bounds exceptions occur
for (int i = 1; i < diff.length()-1; i++) {
if (diff.charAt(i-1) != 'z' &&
diff.charAt(i+1) != 'p') {
s += diff.charAt(i);
}
}
return s;
}
This is successful for a few of them but not for others. It seems like the && operator is acting like a || for some of the example strings; that is to say, many of the characters I want to keep are not being kept. I'm not sure how I would go about fixing it.
A nudge in the right direction if you please! I just need a hint!
Actually it is the other way around. You should do:
if (diff.charAt(i-1) != 'z' || diff.charAt(i+1) != 'p') {
s += diff.charAt(i);
}
Which is equivalent to:
if (!(diff.charAt(i-1) == 'z' && diff.charAt(i+1) == 'p')) {
s += diff.charAt(i);
}
This sounds like the perfect use of a regular expression.
The regex "z.p" will match any three letter token starting with a z, having any character in the middle, and ending in p. If you require it to be a letter you could use "z[a-zA-Z]p" instead.
So you end up with
public String zipZap(String str) {
return str.replaceAll("z[a-zA-Z]p", "zp");
}
This passes all the tests, by the way.
You could make the argument that this question is about raw string manipulation, but I would argue that that makes this an even better lesson: applying regexes appropriately is a massively useful skill to have!
public String zipZap(String str) {
//If bigger than 3, because obviously without 3 variables we just return the string.
if (str.length() >= 3)
{
//Create a variable to return at the end.
String ret = "";
//This is a cheat I worked on to get the ending to work easier.
//I noticed that it wouldn't add at the end, so I fixed it using this cheat.
int minusAmt = 2;
//The minus amount starts with 2, but can be changed to 0 when there is no instance of z-p.
for (int i = 0; i < str.length() - minusAmt; i++)
{
//I thought this was a genius solution, so I suprised myself.
if (str.charAt(i) == 'z' && str.charAt(i+2) == 'p')
{
//Add "zp" to the return string
ret = ret + "zp";
//As long as z-p occurs, we keep the minus amount at 2.
minusAmt = 2;
//Increment to skip over z-p.
i += 2;
}
//If it isn't z-p, we do this.
else
{
//Add the character
ret = ret + str.charAt(i);
//Make the minus amount 0, so that we can get the rest of the chars.
minusAmt = 0;
}
}
//return the string.
return ret;
}
//If it was less than 3 chars, we return the string.
else
{
return str;
}
}

How can I find the index of the first "element" in my string using Java?

I'm working on writing a simple Prolog interpreter in Java.
How can I find the last character index of the first element either the head element or the tail element of a string in "List Syntax"?
List Syntax looks like:
(X)
(p a b)
(func (func2 a) (func3 X Y))
(equal eve (mother cain))
The head for each of those strings in order are:
Head: "X", Index: 1
Head: "p", Index: 1
Head: "func", Index: 4
Head: "equal", Index: 5
Basically, I need to match the string that immediately follows the first "(" and ends either with a space or a closing ")", whichever comes first. I need the character index of the last character of the head element.
How can I match and get this index in Java?
Brabster's solution is really close. However, consider the case of:
((b X) Y)
Where the head element is (b x). I attempted to fix it by removing "(" from the scanner delimiters but it still hiccups because of the space between "b" and "x".
Similarly:
((((b W) X) Y) Z)
Where the head is (((b w) x) Y).
Java's Scanner class (introduced in Java 1.5) might be a good place to start.
Here's an example that I think does what you want (updated to include char counting capability)
public class Test {
public static void main(String[] args) {
String[] data = new String[] {
"(X)",
"(p a b)",
"(func (func2 a) (func3 X Y))",
"(equal eve (mother cain))",
"((b X) Y)",
"((((b W) X) Y) Z)"
};
for (String line:data) {
int headIdx = 0;
if (line.charAt(1) == '(') {
headIdx = countBrackets(line);
} else {
String head = "";
Scanner s = new Scanner(line);
s.useDelimiter("[)|(| ]");
head = s.next();
headIdx = line.indexOf(head) + head.length() - 1;
}
System.out.println(headIdx);
}
}
private static int countBrackets(String line) {
int bracketCount = 0;
int charCount = 0;
for (int i = 1; i < line.length(); i++) {
char c = line.charAt(i);
if (c == '(') {
bracketCount++;
} else if (c == ')') {
bracketCount--;
}
if (bracketCount == 0) {
return charCount + 1;
}
charCount++;
}
throw new IllegalStateException("Brackets not nested properly");
}
}
Output:
1
1
4
5
5
13
It's not a very elegant solution, but regexes can't count (i.e. brackets). I'd be thinking about using a parser generator if there's any more complexity in there :)
Is there a reason you can't just brute force it? Something like this?
public int firstIndex( String exp ) {
int parenCount = 0;
for (int i = 1; i < exp.length(); i++) {
if (exp.charAt(i) == '(') {
parenCount++;
}
else if (exp.charAt(i) == ')') {
parenCount--;
}
if (parenCount == 0 && (exp.charAt(i+1) == ' ' || exp.charAt(i) == ')')) {
return i;
}
}
}
I may be missing something here, but I think that would work.
I suggest you write a proper parser (operator precedence in the case of Prolog) and represent the terms as trees of Java objects for further processing.

Categories