Java extract integers from a string containing delimiters and range symbols - java

Is there a library that can help me split a String to integers by delimiters and range marks?
for instance
values="32,38,42-48,84"
output:
int[] = 32,38,42,43,44,45,46,47,48,84

You can use builtin java functions of string class like split and contains to achieve it. In order to convert string to int use Integer.parseInt. E.g.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SimpleParser {
public static void main(String[] args) {
String input = "32,38,42-48,84";
String[] chunks = input.split(",");
System.out.println(Arrays.toString(chunks));
List<Integer> ints = new ArrayList<>();
for (String chunk : chunks) {
if (chunk.contains("-")) {
String[] rangeChunks = chunk.split("-");
if (rangeChunks.length != 2) {
throw new IllegalArgumentException("Invalid range");
}
for (int i = Integer.parseInt(rangeChunks[0]); i <= Integer.parseInt(rangeChunks[1]) ; i++) {
ints.add(i);
}
}else {
ints.add(Integer.parseInt(chunk));
}
}
System.out.println(ints);
}
}
Outputs
[32, 38, 42, 43, 44, 45, 46, 47, 48, 84]

If what you want is to get the whole range (From 42-55 for example), then I'm not entirely sure, but you can always use Regular Expressions to find everything that's not a number . The expression could be "[^0-9] Then use replace and change by some character (e.g commas). Then just split by commas. Feel free to read more about this here: http://www.vogella.com/tutorials/JavaRegularExpressions/article.html (NOTE: I'm not related in any way to Vogella. I just liked the tuto :)
EDIT:
I can now see the output you want (which I believe wasn't there). If that's what you want, then find all split by commas first. After, check if you have elements in which you have a symbol (- for example), and if so, then split by it and use the numbers to create the range. Here's an example of a working code:
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
String[] splitted = s.split(",");
for(int i = 0; i < splitted.length;i++){
if(splitted[i].contains("-")){
String[] nums = splitted[i].split("-");
int from = Integer.parseInt(nums[0]);
int to = Integer.parseInt(nums[1]);
for(int j = from;j <= to;j++)
System.out.print(j+",");
}
else
System.out.print(splitted[i] + ",");
}
Might not be the most efficient solution, but it works.

Get the individual items
//Creates an array of numbers (e.g. "32") and ranges (e.g. "42-48")
String[] items = String.split(",");
Loop through the array and split into ranges if range mark exists
if (items[i].contains("-")
{
//creates an array of two containing the start and end of range
String[] ranges = items[i].split("-");
}
Then for each String you have in your arrays, parse out the Integer
Integer parsedInt = Integer.parseInt(item[i]);
Lastly, convert and add the items to a collection like ArrayList then convert the ranges and loop through the range (42-48), adding the numbers to the collection as well.

I have used simple String arrays ans array list for the solution:
String[] values_s = items.split(",")
List<Integer> values_i = new ArrayList<Integer>();
for(String s: values_s){
if ( s.contains('-') ){
int sum = 0;
String[] g = s.split("-");
for (int i=Integer.parseInt(g[0]); i<Integer.parseInt(g[g.length-1]); i++)
values_i.add(i);
} else {
values_i.add(Integer.parseInt(s));
}
}
int[] n = (int[])values_i.toArray(int[values_i.size()]);
That should do it.

Related

Casting string to integer array [duplicate]

//convert the comma separated numeric string into the array of int.
public class HelloWorld
{
public static void main(String[] args)
{
// line is the input which have the comma separated number
String line = "1,2,3,1,2,2,1,2,3,";
// 1 > split
String[] inputNumber = line.split(",");
// 1.1 > declare int array
int number []= new int[10];
// 2 > convert the String into int and save it in int array.
for(int i=0; i<inputNumber.length;i++){
number[i]=Integer.parseInt(inputNumber[i]);
}
}
}
Is it their any better solution of doing it. please suggest or it is the only best solution of doing it.
My main aim of this question is to find the best solution.
Java 8 streams offer a nice and clean solution:
String line = "1,2,3,1,2,2,1,2,3,";
int[] numbers = Arrays.stream(line.split(",")).mapToInt(Integer::parseInt).toArray();
Edit: Since you asked for Java 7 - what you do is already pretty good, I changed just one detail. You should initialize the array with inputNumber.length so your code does not break if the input String changes.
Edit2: I also changed the naming a bit to make the code clearer.
String line = "1,2,3,1,2,2,1,2,3,";
String[] tokens = line.split(",");
int[] numbers = new int[tokens.length];
for (int i = 0; i < tokens.length; i++) {
numbers[i] = Integer.parseInt(tokens[i]);
}
By doing it in Java 7, you can get the String array first, then convert it to int array:
String[] tokens = line.split(",");
int[] nums = new int[tokens.length];
for(int x=0; x<tokens.length; x++)
nums[x] = Integer.parseInt(tokens[x]);
Since you don't like Java 8, here is the Bestâ„¢ solution using some Guava utilities:
int[] numbers = Ints.toArray(
Lists.transform(
Splitter.on(',')
.omitEmptyStrings()
.splitToList("1,2,3,1,2,2,1,2,3,"),
Ints.stringConverter()));

Splitting a String, from an input File with char and ints

I'm trying to split some input code from a file a certain way and am completely lost on how to do it. I have the file reading incorrectly. I'm just not sure how to split it the way I want it. I currently have it set up like this (below) and it works fine I'm just wondering if there's a way to split it again or something, the lines from the file look as followed:
"Y8 T L6 L2 T Y3" the numbers or letters could vary, and might or might not have a number, I would set it up so I can have every character and number separated into their own String[], how can I do this? the way I have it set up now takes the number along with the character and I don't want that as I need access to the numerical values, thanks.
Code
{
File file = new File(FileName);
Scanner scanner = new Scanner(file);
String currentLine = scanner.nextLine();
String[] seperated = currentLine.split(" ");
}
You can indeed continue with what you have. Since you've read everything in and separated it into a String array, you can loop over the elements in the array and check to see if they have a number following them. The code I'm going to post assumes that each input is either 1) a single letter or 2) a single letter followed by a single number:
for (String temp : seperated) {
int numberIWant;
if (temp.length() == 2) {
numberIWant = temp.charAt(1);
}
//Do something with this number, if you need the letter as well
//Use temp.charAt(0)
If your interest is just having the two separate arrays, then you may not need to split. Just remove the white space and separate the numbers from the other characters.
import java.util.ArrayList;
import java.util.List;
public class App {
public static void main(String[] args) {
String currentLine = "Y8 T L6 L2 T Y3";
//Remove the spaces
String withoutSpaces = currentLine.replace(" ", "");
String[] characters = withoutSpaces.split("");
List<Integer> numeric = new ArrayList<>();
List<String> character = new ArrayList<>();
for (String each : characters) {
if (isNum(each)) {
numeric.add(Integer.parseInt(each));
} else {
character.add(each);
}
}
Integer[] numarray = numeric.toArray(new Integer[numeric.size()]);
String[] chararray = character.toArray(new String[character.size()]);
for(Integer num: numarray){
System.out.println(num);
}
for(String charac: chararray){
System.out.println(charac);
}
}
public static boolean isNum(String strNum) {
boolean ret = true;
try {
Double.parseDouble(strNum);
} catch (NumberFormatException e) {
ret = false;
}
return ret;
}
}

Java: Finding jumbled word

In my country there is Game Show called Slagalica where one of the tasks is to find longest word in array of 12 letters. Size of the longest word is always 10, 11 or 12.
I have file with words from my language I use as database. Words that have 10, 11 or 12 letters in them I've saved in List (listWordSize10_11_12).
When I enter jumbled word [12 letters] in I want from my program to find what word is that originally. I know how to make it work when jumbled word is 12 letters word but I can't work it out when it's less.
Example: 10 letter word is jumbled + 2 random letters.
Goal is for that 10 letter word to be recognized and printed in original state.
Where is what I've done:
// un-jumbling word
System.out.println("Unesite rijec koja treba da se desifruje: ");
String jumbledWord = tast.nextLine();
char[] letter = jumbledWord.toCharArray();
Arrays.sort(letter);
String sorted_Mistery_Word = new String(letter);
for (int i = 0; i < listWordSize10_11_12.size(); i++) {
int exception = 0;
char[] letter_2 = listWordSize10_11_12.get(i).toCharArray();
Arrays.sort(letter_2);
String longWords = new String(letter_2);
int j = i;
while(longWords.length()>i){
if(sorted_Mistery_Word.charAt(j)!=longWords.charAt(i)){
exception++;
j++;
}
}
if(exception < 3){
System.out.println("Your word is: "+listWordSize10_11_12.get(i));
break;
}
}
Thanks!!!
P.S. This is not a homework or some job, just project I've been doing for fun!
Thanks everyone for the help, I've learned a lot!
Your basic approach for 12 characters, which I would characterize as fingerprinting, will also work for 10 or 11 letter words with some modification.
That is, rather that just sorting the letters in each candidate word as you examine it to create the fingerprint, pre-process your array to create a small(ish) fingerprint of each word as a byte[]. Using the English alphabet and ignoring case, for example, you could create a 26-byte array for each word, where each byte position contained the count of each letter in the word.
That is fingerprint[0] contains the number of 'a' characters in the word, and fingerprint[25] the number of 'z' characters.
Then just replace your sorted_Mistery_Word.charAt(j)!=longWords.charAt(i) check with a loop that increments a temporary array for each letter in the mystery word. Finally, check that the temporary array has at least the same value for every position. Something like:
byte [] makeFingerprint(String s) {
byte[] fingerprint = new byte[26];
for (char c : letter_2) {
fingerprint[c - 'a']++;
}
return fingerprint;
}
/** determine if sub is a subset of super */
boolean isSubset(byte[] sub, byte[] super) {
for (int i=0; i < sub.length; i++) {
if (sub[i] > super[i])
return false;
}
return true;
}
void findMatch(String jumbledWord) {
byte[] fingerprint = makeFingerprint(jumbledWord);
for (byte[] candidate : fingerprintList) {
if (isSubset(fingerprint, candidate)) {
System.out.println("Your word is: " + ...);
break;
}
}
}
Here I omitted the creation of the fingerprintList - but it just involves fingerprint each word.
There are plenty of optimizations possible, but this should already be quite a bit faster than your version (and is "garbage free" in the main loop). It can handle candidates of any length (not just 10-12 chars). The biggest optimization, if you will check many words, is to try to use the "fingerpint" as a key for direct lookup. For the 12 character case this is trivial (direct lookup), but for the 10 and 11 or this you would likely have to use type of technique for higher-dimensional searching - locality sensitive hashing seems like a natural fit.
Here's one way to go about the problem. Let's say (since no example input was provided) that there's 3 String[]'s, arr3 (that represents the 10-letter-words you have), arr4 (that represents the 11-letter-words you have), and arr5 (you guessed it, represents the 12-letter words you have). This is what I made for those:
String[] arr3 = { "map", "cat", "dog" };
String[] arr4 = { "four", "five", "nine" };
String[] arr5 = { "funny", "comma", "brace" };
So based on what you said, if we got the input of pam, we'd want the output of map. If we got the input of enni we'd want the output of nine. And if we got the input of yfunn we'd want the output of funny. So how to go about doing this? I like what #cricket_007 mentioned about using maps. But first, let's get the permutations down.
Based off of the linked SO question, I came up with this modified/variation to get the jumbled text:
public static List<String> jumble(String str) {
List<String> result = new ArrayList<String>();
permutation(result, "", str);
return result;
}
private static void permutation(List<String> l, String prefix, String s) {
int n = s.length();
if (n == 0) {
l.add(prefix);
} else {
for (int i = 0; i < n; i++)
permutation(l, prefix + s.charAt(i), s.substring(0, i) + s.substring(i + 1, n));
}
}
This code will let us easily construct a single map for us to store jumbled text in as a key, and the answer to that jumbled text as a value.
All together, the final code looks like this:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Appy {
public static void main(String[] args) {
String[] arr3 = { "map", "cat", "dog" };
String[] arr4 = { "four", "five", "nine" };
String[] arr5 = { "funny", "comma", "brace" };
List<String> permutations = new ArrayList<String>();
Map<String, String> map = new HashMap<String, String>();
for (String s : arr3) {
permutations = jumble(s);
for (String str : permutations)
map.put(str, s);
}
for (String s : arr4) {
permutations = jumble(s);
for (String str : permutations)
map.put(str, s);
}
for (String s : arr5) {
permutations = jumble(s);
for (String str : permutations)
map.put(str, s);
}
System.out.println("test = 'pam' -> " + map.get("pam"));
System.out.println("test = 'enni' -> " + map.get("enni"));
System.out.println("test = 'yfunn' -> " + map.get("yfunn"));
}
public static List<String> jumble(String str) {
List<String> result = new ArrayList<String>();
permutation(result, "", str);
return result;
}
private static void permutation(List<String> l, String prefix, String s) {
int n = s.length();
if (n == 0) {
l.add(prefix);
} else {
for (int i = 0; i < n; i++)
permutation(l, prefix + s.charAt(i), s.substring(0, i) + s.substring(i + 1, n));
}
}
}
Which gives the resulting output of:
test = 'pam' -> map
test = 'enni' -> nine
test = 'yfunn' -> funny
Now applying this logic, adapting for your case of 10, 11, and 12 letter words should be relatively simple. Cheers!

Splitting input into integers

I am trying to split the input that I get through a scanner and split the integers inside the square brackets and put all of them into separate tree sets and perform operations based on the operators in the line. I am having issues with trying to parse the input and add the into the different tree sets, I keep getting InputMismatchExceptioneven after casting it to an integer. Would like to know where I am going wrong.
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int times = in.nextInt();
//iterate through number of times
for (int i = 0; i < times; i++) {
int num = in.nextInt();
System.out.println(num)
}
}
}
The input I take in is
6
[1,2,3] + [1,4,5]
[5,4,7,11] - [5,7]
[1,2,3] * [1,4,5]
[5,17,51,2,51] + [1,3,12,5,44,66,82]
[7,13,23,11,10] - [11,13,14,7,8,9,10]
[7,13,23,11,10] * [11,13,14,7,8,9,10]
Where my question is from
nextInt can't properly parse characters like [, ], , or + (if it is separated from number like + 4 instead of +4 which would simply represent 4).
That is why when you are trying to parse String like [1,2,3] + [3,4] with nextInt you are getting InputMismatchException because of [.
Probably one of simplest ways to parse your file is in a way like
int times = in.nextInt();
in.nextLine();//nextInt will not consume line separator, we need to do it explicitly
for (int i = 0; i < times; i++) {
String line = in.nextLine();
parse(line);
}
where parse method could be in from
private static final Pattern p = Pattern
.compile("\\[(?<set1>\\d+(?:,\\d+)*)\\]" // match first [1,2,3] and place it in group named set1
+ "\\s(?<operator>[-+*])\\s" // match operator, one of - + or *
+ "\\[(?<set2>\\d+(?:,\\d+)*)\\]"); // match second [2,3,4] and place in group named set2
private static void parse(String text) {
Matcher m = p.matcher(text);
if (m.matches()) {
String[] set1 = m.group("set1").split(",");
String[] set2 = m.group("set2").split(",");
String operator = m.group("operator");
if (operator.equals("+")){
//handle sum of sets
}
//handle rest of operators
else if (operator.equals("-")){
//...
}
//...
} else {
System.out.println("wrong text format:");
System.out.println(text);
}
}

How do I grab the numbers in a String array and place them into an int array

I have a String array that contains {127,a,0,10}. I want to grab the numbers in that array and place them into an int array that will now contain {127,0,10}.
I tried to use parseInt on each individual value in the String array but it does not worked on characters in a string.
Thank you!
The Java 8 answer:
int[] results = Arrays.stream(arr)
.filter(s -> s.matches("-?[0-9]+"))
.mapToInt(s -> Integer.parseInt(s))
.toArray();
EDIT: Even better:
int[] results = Arrays.stream(arr)
.filter(s -> s.matches("-?[0-9]+"))
.mapToInt(Integer::parseInt)
.toArray();
demonstrating yet another new cool language feature. I should have seen this the first time. It's pathetic that I haven't yet mastered Java 8 despite its being officially available for a whole two weeks now.
Validate int value
You could create a function that would tell you if a string represents valid int value as so:
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
}
// only got here if we didn't return false
return true;
}
Source: Determine if a String is an Integer in Java
Remove unwanted elements
You can now easily loop on the array and remove unwanted elements as so:
for(int i=0; i< myStringArray.length(); i++){
if(!isInteger(myStringArray[i])){
myStringArray[i]=null;
}
}
I tried to use parseInt on each individual value in the String array
but it does not worked on characters in a string.
parseInt does not work for characters, that is by design of that API. It will throw an exception in case of invalid numeric value. So what you have to do is encapsulate your code in try/catch. And in case of NumberFormatException don't put the item in second array, otherwise add. Hope you will be able to code this.
Try something like this
Integer[] numberArray = new Integer[stringArray.length];
int index = 0;
for(String s : stringArray) {
try {
Integer stringAsNumber = Interger.valueOf(s);
numberArray[index] = stringAsNumber;
index++;
} catch(NumberFormatException nfe) {
//String is not a valid number
}
}
return numberArray;
You can use a regex to determine if a string can be parsed into an Integer.
String [] arr = {"1233", "45", "a34", "/", "0", "19"};
for(int i = 0; i < arr.length; i++)
if(arr[i].matches("-?[0-9]+"))
System.out.println(arr[i]);
The rest is easy to do.
EDIT: This detects both positive and negative numbers.
try this..
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.ArrayList;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String[] var = new String[]{"127","a","0","10"};
List<Integer> var2 = new ArrayList<Integer>();
//Integer extraction
for (String s : var)
{
try{
var2.add(Integer.parseInt(s));
System.out.println(Integer.parseInt(s));
}catch(NumberFormatException e){}
}
//int array if you want array only or you just use List<Integer>
int[] array = new int[var2.size()];
for(int i = 0; i < var2.size(); i++) array[i] = var2.get(i);
}
}

Categories

Resources