How to split a string into only positive and negative integers? - java

I'm writing a program to do different calculations with vector functions, but the program I have as of now delimits the negative digits. I've tried using different delimiters but I can't seem to get the right one.
Does anyone know how to keep the positive and negative digits when splitting a string? Also, is there a way to keep any decimal values? .45 would return 45 and .29 would return 29
This is the code:
ArrayList<Integer> list = new ArrayList<Integer>();
String twoVectors = "a=<-1,2,-3> b=<4,-5,6>"; // vector and a and b
String[] tokens = twoVectors.split("\\D");
for (String s : tokens)
if (!s.equals(""))
list.add(Integer.parseInt(s));
System.out.println(Arrays.toString(list.toArray()));
When I run the program I get [1, 2, 3, 4, 5, 6] instead of [-1, 2, -3, 4, -5, 6]. All the functions I have worked perfectly fine but dont work when using negative values.
Any help would be appreciated.

You can use
String[] tokens = twoVectors.split("[^\\d-]+");
[^\\d-]+ : match anything except digits and -
[] : match everything mentioned inside []
^ : negation mean do not match (\\d-)
\\d- : digits 0-9 and - character
Regex Demo
String twoVectors = "a=<-1,2,-3> b=<4,-5,6>";
ArrayList<Integer> list = new ArrayList<Integer>();
String[] tokens = twoVectors.split("[^\\d-]");
for (String s : tokens)
if (!s.equals(""))
list.add(Integer.parseInt(s));
System.out.println(Arrays.toString(list.toArray()));
Output :
[-1, 2, -3, 4, -5, 6]
Or
you can use Pattern along with matcher to find all the desired values i.e singed or unsigned numbers with -?\\d+ regex
Regex Demo -?\d+
Update : For Double values , you can use [^\\d-.]+ and make sure to use Double instead of Integer along with Double.parseDouble
And with Pattern and Matcher use -?\\d*\\.?\\d+

Use [^\\d-] inside your split method i.e. twoVectors.split("[^\\d-]")
Why [^\\d-]:
^ : Finds regex that must match at the beginning of the line.
\d : Any digit from [0-9]
- : will match '-' if it exists

The regex that you currently have splits the string on anything but digits. So anything that is not a digit is considered a splitter. If you added - sign to this pattern, anything that is not a digit or a - sign will be included. This will work for some cases, but will fail if you have - or . without a number afterwards.
What you need to do is to specify the number format in a regex (like -?\d*.?\d+), and then find all matches of this pattern. You will also need to change the numbers to Double so that you can parse decimal numbers.
String twoVectors = "a=<-1,.2,-3> b=<4,-5,6>";
ArrayList<Double> numbers = new ArrayList<Double>();
Matcher matcher = Pattern.compile("-?\\d*\\.?\\d+").matcher(twoVectors);
while (matcher.find()) {
numbers.add(Double.parseDouble(matcher.group()));
}
System.out.println(Arrays.toString(numbers.toArray()));
Output
[-1.0, 0.2, -3.0, 4.0, -5.0, 6.0]

A 1-line solution:
List<Integer> numbers = Arrays
.stream(twoVectors.replaceAll("^[^\\d-]+", "").split("[^\\d-]+"))
.map(Integer::new)
.collect(Collectors.toList());
The initial replace is to remove the leading non-target chars (otherwise the split would return a blank in the first element).

Related

Java Regex : 4 Letters followed by 2 Integers

Regex beginner here.
Already visited the followings, none answers my question :
1, 2, 3, 4, 5, 6, etc.
I have a simple regex to check if a string contains 4 chars followed by 2 digits.
[A-Za-z]{4}[0-9]{2}
But, when using it, it doesn't matches. Here is the method I use and an example of input and output :
Input in a JPasswordField
Mypass85
Output
false
Method
public static boolean checkPass(char[] ca){
String s = new String(ca);
System.out.println(s); // Prints : Mypass85
p = Pattern.compile("[A-Za-z]{4}[0-9]{2}");
return p.matcher(s).matches();
}
Matcher#matches attempts to match full input. Use Matcher#find instead:
public static boolean checkPass(String s){
System.out.println(s); // Prints : Mypass85
p = Pattern.compile("[A-Za-z]{4}[0-9]{2}");
return p.matcher(s).find();
}
Promoting a comment to an answer.
It doesn't match because "Mypass85" is 6 letters followed by 2 numbers, but your pattern expects exactly 4 letters followed by 2 numbers.
You can either pass something like "Pass85" to match your existing pattern, or you can get "Mypass85" to match by changing the {4} to {6} or to {4,} (4 or more).

Java - Extract string from pattern

Given some strings that look like this:
(((((((((((((4)+13)*5)/1)+7)+12)*3)-6)-11)+9)*2)/8)-10)
(((((((((((((4)+13)*6)/1)+5)+12)*2)-7)-11)+8)*3)/9)-10)
(((((((((((((4)+13)*6)/1)+7)+12)*2)-8)-11)+5)*3)/9)-10)
(btw, they are solutions for a puzzle which I write a program for :) )
They all share this pattern
"(((((((((((((.)+13)*.)/.)+.)+12)*.)-.)-11)+.)*.)/.)-10)"
For 1 solution : How can I get the values with this given pattern?
So for the first solution I will get an collection,list,array (doesn't matter) like this:
[4,5,1,7,3,6,9,2,8]
You've done most of the work actually by providing the pattern. All you need to do is use capturing groups where the . are (and escape the rest).
I put your inputs in a String array and got the results into a List of integers (as you said, you can change it to something else). As for the pattern, you want to capture the dots; this is done by surrounding them with ( and ). The problem in your case is that the whole string is full of them, so we need to quote / escape them out (meaning, tell the regex compiler that we mean the literal / character ( and )). This can be done by putting the part we want to escape between \Q and \E.
The code below shows a coherent (though maybe not effective) way to do this. Just be careful with using the right amount of \ in the right places:
public class Example {
public static void main(String[] args) {
String[] inputs = new String[3];
inputs[0] = "(((((((((((((4)+13)*5)/1)+7)+12)*3)-6)-11)+9)*2)/8)-10)";
inputs[1] = "(((((((((((((4)+13)*6)/1)+5)+12)*2)-7)-11)+8)*3)/9)-10)";
inputs[2] = "(((((((((((((4)+13)*6)/1)+7)+12)*2)-8)-11)+5)*3)/9)-10)";
List<Integer> results;
String pattern = "(((((((((((((.)+13)*.)/.)+.)+12)*.)-.)-11)+.)*.)/.)-10)"; // Copy-paste from your question.
pattern = pattern.replaceAll("\\.", "\\\\E(.)\\\\Q");
pattern = "\\Q" + pattern;
Pattern p = Pattern.compile(pattern);
Matcher m;
for (String input : inputs) {
m = p.matcher(input);
results = new ArrayList<>();
if (m.matches()) {
for (int i = 1; i < m.groupCount() + 1; i++) {
results.add(Integer.parseInt(m.group(i)));
}
}
System.out.println(results);
}
}
}
Output:
[4, 5, 1, 7, 3, 6, 9, 2, 8]
[4, 6, 1, 5, 2, 7, 8, 3, 9]
[4, 6, 1, 7, 2, 8, 5, 3, 9]
Notes:
You are using a single ., which means
Any character (may or may not match line terminators)
So if you have a number there which is not a single digit or a single character which is not a number (digit), something will go wrong either in the matches or parseInt. Consider \\d to signify a single digit or \\d+ for a number instead.
See Pattern for more info on regex in Java.

Split numbers from String array in java

String Equation = input.nextLine();
String[] number = Equation.split("\d+");
I want to split all digits come into string and dump into number. How'd do it?
like Equation is : 2x^4 - 45y^4
it should be dumped in number on index as : {2, 4 , 45, 4};
You can split on one or more non-digit characters - \\D+:
String[] number = equation.split("\\D+");
While working with Java regex, you need to double escape the \d, \D, so on. And please follow Java naming convention. Your variable should be named equation, not Equation.
What I'd do is String.replaceAll all non-digits with whitespace. Then String.split by whitespace.
package com.sandbox;
import java.util.Arrays;
public class Sandbox {
public static void main(String[] args) {
String input = "2x^4 - 45y^4";
input = input.replaceAll("\\D", " ");
String[] parts = input.split("\\W+");
System.out.println(Arrays.toString(parts));
}
}
This will print "[2, 4, 45, 4]"
Now that I understand #RohitJain's answer, it seems I'm including an unnecessary step. I guess I'll leave this here anyway since it does work, but I recommend his solution. His solution splits on all non digits. Since split excludes the delimiter, this also removes the non-digits.

Split a String at every 3rd comma in Java

I have a string that looks like this:
0,0,1,2,4,5,3,4,6
What I want returned is a String[] that was split after every 3rd comma, so the result would look like this:
[ "0,0,1", "2,4,5", "3,4,6" ]
I have found similar functions but they don't split at n-th amount of commas.
NOTE: while solution using split may work (last test on Java 17) it is based on bug since look-ahead in Java should have obvious maximum length. This limitation should theoretically prevent us from using + but somehow \G at start lets us use + here. In the future this bug may be fixed which means that split will stop working.
Safer approach would be using Matcher#find like
String data = "0,0,1,2,4,5,3,4,6";
Pattern p = Pattern.compile("\\d+,\\d+,\\d+");//no look-ahead needed
Matcher m = p.matcher(data);
List<String> parts = new ArrayList<>();
while(m.find()){
parts.add(m.group());
}
String[] result = parts.toArray(new String[0]);
You can try to use split method with (?<=\\G\\d+,\\d+,\\d+), regex
Demo
String data = "0,0,1,2,4,5,3,4,6";
String[] array = data.split("(?<=\\G\\d+,\\d+,\\d+),"); //Magic :)
// to reveal magic see explanation below answer
for(String s : array){
System.out.println(s);
}
output:
0,0,1
2,4,5
3,4,6
Explanation
\\d means one digit, same as [0-9], like 0 or 3
\\d+ means one or more digits like 1 or 23
\\d+, means one or more digits with comma after it, like 1, or 234,
\\d+,\\d+,\\d+ will accept three numbers with commas between them like 12,3,456
\\G means last match, or if there is none (in case of first usage) start of the string
(?<=...), is positive look-behind which will match comma , that has also some string described in (?<=...) before it
(?<=\\G\\d+,\\d+,\\d+), so will try to find comma that has three numbers before it, and these numbers have aether start of the string before it (like ^0,0,1 in your example) or previously matched comma, like 2,4,5 and 3,4,6.
Also in case you want to use other characters then digits you can also use other set of characters like
\\w which will match alphabetic characters, digits and _
\\S everything that is not white space
[^,] everything that is not comma
... and so on. More info in Pattern documentation
By the way, this form will work with split on every 3rd, 5th, 7th, (and other odd numbers) comma, like split("(?<=\\G\\w+,\\w+,\\w+,\\w+,\\w+),") will split on every 5th comma.
To split on every 2nd, 4th, 6th, 8th (and rest of even numbers) comma you will need to replace + with {1,maxLengthOfNumber} like split("(?<=\\G\\w{1,3},\\w{1,3},\\w{1,3},\\w{1,3}),") to split on every 4th comma when numbers can have max 3 digits (0, 00, 12, 000, 123, 412, 999).
To split on every 2nd comma you can also use this regex split("(?<!\\G\\d+),") based on my previous answer
Obligatory Guava answer:
String input = "0,0,1,2,4,5,3,4,6";
String delimiter = ",";
int partitionSize = 3;
for (Iterable<String> iterable : Iterables.partition(Splitter.on(delimiter).split(s), partitionSize)) {
System.out.println(Joiner.on(delimiter).join(iterable));
}
Outputs:
0,0,1
2,4,5
3,4,6
Try something like the below:
public String[] mySplitIntoThree(String str)
{
String[] parts = str.split(",");
List<String> strList = new ArrayList<String>();
for(int x = 0; x < parts.length - 2; x = x+3)
{
String tmpStr = parts[x] + "," + parts[x+1] + "," + parts[x+2];
strList.add(tmpStr);
}
return strList.toArray(new String[strList.size()]);
}
(You may need to import java.util.ArrayList and java.util.List)
Nice one for the coding dojo! Here's my good old-fashioned C-style answer:
If we call the bits between commas 'parts', and the results that get split off 'substrings' then:
n is the amount of parts found so far,
i is the start of the next part,
startIndex the start of the current substring
Iterate over the parts, every third part: chop off a substring.
Add the leftover part at the end to the result when you run out of commas.
List<String> result = new ArrayList<String>();
int startIndex = 0;
int n = 0;
for (int i = x.indexOf(',') + 1; i > 0; i = x.indexOf(',', i) + 1, n++) {
if (n % 3 == 2) {
result.add(x.substring(startIndex, i - 1));
startIndex = i;
}
}
result.add(x.substring(startIndex));

Splitting string expression into tokens

My input is like
String str = "-1.33E+4-helloeeee+4+(5*2(10/2)5*10)/2";
i want the output as:
1.33E+4
helloeeee
4
5
2
10
2
5
10
2
But I am getting the output as
1.33, 4, helloeeee, 4, 5, 2, 10, 2, 5, 10, 2
i want the exponent value completely after splitting "1.33e+4"
here is my code:
String str = "-1.33E+4-helloeeee+4+(5*2(10/2)5*10)/2";
List<String> tokensOfExpression = new ArrayList<String>();
String[] tokens=str.split("[(?!E)+*\\-/()]+");
for(String token:tokens)
{
System.out.println(token);
tokensOfExpression.add(token);
}
if(tokensOfExpression.get(0).equals(""))
{
tokensOfExpression.remove(0);
}
I would first replace the E+ with a symbol that is not ambiguous such as
str.ReplaceAll("E+","SCINOT");
You can then parse with StringTokenizer, replacing the SCINOT symbol when you need to evaluate the number represented in scientific notation.
You can't do that with a single regular expression, because of the ambiguities introduced by FP constants in scientific notation, and in any case you need to know which token is which without having to re-scan them. You've also mis-stated your requirement, as you certainly need the binary operators in the output as well. You need to write both a scanner and a parser. Have a look for 'recursive descent expression parser' and 'Dijkstra shunting-yard algorithm'.Resetting the digest is redundant.
Try this
String[] tokens=str.split("(?<!E)+[*\\-/()+]");
It's easier to achieve the result with Matcher
String str = "-1.33E+4-helloeeee+4+(5*2(10/2)5*10)/2";
Matcher m = Pattern.compile("\\d+\\.\\d*E[+-]?\\d+|\\w+").matcher(str);
while(m.find()) {
System.out.println(m.group());
}
prints
1.33E+4
helloeeee
4
5
2
10
2
5
10
2
note that it needs some testing for different floating point expressions but it is easily adjustable

Categories