Related
I have a method that returns some kind of string. I want to store the individual words in a HashMap with their number of occurrences?
public static void main(String[] args) {
String s = "{link:hagdjh, matrics:[{name:apple, value:1},{name:jeeva, value:2},{name:abc, value:0}]}";
String[] strs = s.split("matrics");
System.out.println("Substrings length:" + strs.length);
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
For eg, I have a string- "{link:https://www.google.co.in/, matrics:[{name:apple, value:1},{name:graph, value:2},{name:abc, value:0}]}";
Now my hashmap should look like
apple = 1
graph = 2
abc = 0
How should I proceed?
I know how to use HashMaps. My problem, in this case, is that I don't know how to parse through the given string and store the words with their number of occurrences.
String regex = "\\{name:(.*), value:(\\d+)\\}";
HashMap<String, Integer> link = new HashMap<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(s);
while (matcher.find()){
String found = matcher.group(1);
String number = matcher.group(2);
link.put(found, Integer.parseInt(number));
}
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
Pattern pattern = Pattern.compile("matrics:\\[\\{(.*?)\\]\\}");
Matcher matcher = pattern
.matcher("{link:hagdjh, matrics:[{name:apple, value:1},{name:jeeva, value:2},{name:abc, value:0}]}");
String data = "";
if (matcher.find()) {
data = matcher.group();
}
List<String> records = new ArrayList<String>();
pattern = Pattern.compile("(?<=\\{).+?(?=\\})");
matcher = pattern.matcher(data);
while (matcher.find()) {
records.add(matcher.group());
}
for (String s : records) {
String[] parts = s.split(", ");
map.put(parts[0].substring(parts[0].indexOf(":") + 1),
Integer.parseInt(parts[1].substring(parts[1].indexOf(":") + 1)));
}
map.entrySet().forEach(entry -> {
System.out.println(entry.getKey() + " = " + entry.getValue());
});
}
}
Output:
apple = 1
jeeva = 2
abc = 0
It appeares that your data is in JSON format.
If it is guaranteed to be in JSON format, you can parse it using JSON parsing library and than analyze the matrics data in a convinient way (code follows).
If the data is not guaranteed to be in JSON format, you can use REGEX to help you parse it, as in Reza soumi's answer.
import org.json.JSONObject;
import org.json.JSONArray;
import java.util.HashMap;
String s = "{link:hagdjh, matrics:[{name:apple, value:1},{name:jeeva, value:2},{name:abc, value:0}]}";
JSONObject obj = new JSONObject(s);
JSONArray matrics = obj.getJSONArray("matrics");
System.out.println(matrics);
HashMap<String, Integer> matricsHashMap = new HashMap<String, Integer>();
for (int i=0;i < matrics.length();i++){
JSONObject matric = matrics.getJSONObject(i);
System.out.println("Adding matric: " + matric + " to hash map");
String matricName = matric.getString("name");
Integer matricValue = Integer.valueOf(matric.getInt("value"));
matricsHashMap.put(matricName, matricValue);
}
System.out.println(matricsHashMap);
Try this:
import static java.lang.System.err;
import static java.lang.System.out;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toMap;
/**
* Counting the words in a String.
*/
public class CountWordsInString
{
/*-----------*\
====** Constants **========================================================
\*-----------*/
/**
* An empty array of {#code ${type_name}} objects.
*/
public static final String INPUT = "{link:https://www.google.co.in/, matrics:[{name:apple, value:1},{name:graph, value:2},{name:abc, value:0}]}";
/*---------*\
====** Methods **==========================================================
\*---------*/
/**
* The program entry point.
*
* #param args The command line arguments.
*/
public static void main( final String... args )
{
try
{
final var result = stream( INPUT.split( "\\W+" ) )
.filter( s -> !s.isBlank() )
.filter( s -> !s.matches( "\\d*" ) )
.collect( groupingBy( s -> s ) )
.entrySet()
.stream()
.collect( toMap( k -> k.getKey(), v -> Long.valueOf( v.getValue().size() ) ) );
out.println( result.getClass() );
for( final var entry : result.entrySet() )
{
out.printf( "'%s' occurred %d times%n", entry.getKey(), entry.getValue() );
}
}
catch( final Throwable t )
{
//---* Handle any previously unhandled exceptions *----------------
t.printStackTrace( err );
}
} // main()
}
// class CountWordsInString
Confessed, not the most obvious solution, but I wanted to have some fun with it, too.
The INPUT.split( "\\W+" ) gives you the words in the string, but also numbers and an 'empty' word at the beginning.
The 'empty' word is eliminated with the first filter() statement, the numbers go with the second.
The first collect( groupingBy() ) gives you a HashMap<String,List<String>>, so I had to convert that to a HashMap<String,Long> in the following steps (basically with the second collect( groupingBy() )).
May be there is a more efficient solution, or one that is more elegant, or even one that is both, more efficient and more elegant … but it works as expected, and I had some fun with it.
The output is:
class java.util.HashMap
'apple' occurred 1 times
'matrics' occurred 1 times
'abc' occurred 1 times
'in' occurred 1 times
'www' occurred 1 times
'name' occurred 3 times
'link' occurred 1 times
'google' occurred 1 times
'https' occurred 1 times
'co' occurred 1 times
'value' occurred 3 times
'graph' occurred 1 times
I'm stumped: ( I have a String array of state abbreviations, and along with that, I have one array for each state abbreviation that contains a number of id numbers as Strings. I then randomly select one of the states from the states array.
I then randomly select an index from the selected state's array.
That all works, but what I can't figure out how to reference the actual element/value.
For example: if my randomly selected state element is "PA" and my randomly selectedStateIndex is an int equal to 1, then how do I return selectedState[selectedStateIndex] value to the calling method?
If I try "String id = selectedState[selectedStateIndex]" I get the following error:
"The type of the expression must be an array type but it resolved to String" in Eclipse. Help! Been trying to figure this out for hours now : (
My code:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
public class Scratchpad {
public static void main(String[] args) {
String destinationCode;
String[] states = {"AL", "AZ", "CA", "FL", "IL", "NY", "NC", "PA", "TN", "TX"};
// TODO - ADD QUOTATION MARKS AROUND ALL THESE STRINGS
String[] AL = {"10035591", "10035650", "10035664", "10035671", "10035676", "10035682", "10050000", "10050330", "10052160", "10052520", "10052930", "10054176", "10054177", "10054178", "10054179", "10055418", "10055453", "10055455", "10055575", "10730150"};
String[] AZ = {"30031316", "30031317", "30031318", "30031319", "30050000", "30050014", "30050023", "30050024", "30050025", "30050037", "30050110", "30050190", "30050330", "30050590", "30050924", "30050925", "30130210"};
String[] CA = {"50010018", "50010020", "50010030", "50010350", "50010540", "50011100", "50011290", "50011450", "50011820", "50012250", "50012350", "50012610", "50012680", "50013080", "50013090", "50013650", "50016650", "50017080", "50017165", "50017841", "50733020"};
String[] FL = {"100010510", "100010520", "100010530", "100011910", "100013222", "100013223", "100013224", "100013225", "100013226", "100013227", "100013228", "100013229", "100013231", "100013232", "100013233", "100013234", "100013235", "100013236", "100013237", "100014227", "100951160"};
String[] IL = {"140010017", "140010028", "140012430", "140014322", "140014352", "140014355", "140014490", "140014609", "140014626", "140014638", "140014682", "140014790", "140014804", "140014971", "140015111", "140015112", "140015113", "140015114", "140015115", "140015117", "140310510"};
String[] NY = {"330010020", "330010490", "330010500", "330011140", "330013050", "330013310", "330013320", "330013360", "330013440", "330014220", "330015000", "330015020", "330015150", "330015190", "330015327", "330015328", "330015359", "330612010"};
String[] NC = {"340032022", "340032841", "340050000", "340051390", "340052023", "340052024", "340052025", "340052026", "340052027", "340052028", "340070000", "340071160", "340072029", "340072031", "340072032", "340072033", "340072034", "340072035", "340072036", "340090000", "340630270"};
String[] PA = {"390010459", "390010759", "390011460", "390012090", "390012300", "390015090", "390017254", "390017255", "390017256", "390017257", "390017258", "390017259", "390017261", "390017262", "390017263", "390017264", "390017266", "390017267", "390017268", "390017271", "391013000"};
String[] TN = {"430010120", "430010660", "430011200", "430011520", "430011591", "430011592", "430011594", "430030000", "430030760", "430031596", "430031597", "430031598", "430031599", "430050000", "430051601", "430052163", "430052165", "430052193", "431570560"};
String[] TX = {"440050000", "440050850", "440051850", "440052323", "440053495", "440059391", "440059544", "440059598", "440059599", "440070000", "440070110", "440072520", "440079602", "440079603", "440090000", "440092199", "440093715", "440094205", "440094445", "440094795", "441571440"};
int randomStateIndex = new Random().nextInt(states.length);
System.out.println("randomStateIndex = " + randomStateIndex);
System.out.println("Selected state: " + states[randomStateIndex]);
String selectedState = states[randomStateIndex];
int selectedStateIndex = new Random().nextInt(selectedState.length());
System.out.println(selectedStateIndex);
}
}
If I try "String id = selectedState[selectedStateIndex]" I get the
following error: "The type of the expression must be an array type but
it resolved to String" in Eclipse. Help! Been trying to figure this
out for hours now : (
As the error clearly says, selectedState is of type String; it is not an array. The square brackets go with a variable of array type.
That all works, but what I can't figure out how to reference the
actual element/value.
You need to use a better data structure so that you can achieve this goal easily. I would recommend Map<String, List<String>>. See the following example:
Map<String, String[]> statedata = new HashMap<>();
statedata.put("AL", new String[]{"10035591", "10035650", "10035664", "10035671", "10035676", "10035682", "10050000", "10050330", "10052160", "10052520", "10052930", "10054176", "10054177", "10054178", "10054179", "10055418", "10055453", "10055455", "10055575", "10730150"});
stateData.put("AZ", new String[]{"30031316", "30031317", "30031318", "30031319", "30050000", "30050014", "30050023", "30050024", "30050025", "30050037", "30050110", "30050190", "30050330", "30050590", "30050924", "30050925", "30130210"});
...
...
String selectedState = states[randomStateIndex];
statedata.get(selectedState)[selectedStateIndex];
Input
I have the following example input (each of those is a bash executable command):
client-properties create mode "publisher" "version" "mode"
client-properties set "publisher" "version" "mode" "prop1" "value
value
value"
client-properties set "publisher" "version" "mo\"de" "prop2" "שלום עליכם"
Output
From that, I want to parse it into 3 String[]s as follows:
{"client-properties", "create", "mode", "publisher", "version", "mode"}
{"client-properties", "set", "publisher", "version", "mode", "prop1", "value\nvalue\nvalue"}
{"client-properties", "set", "publisher", "version", "mo\"de", "prop2", "שלום עליכם"}
// (mo"de)
Requirements
The hard requirements are as follows:
Newlines denote new statements.
Spaces denote single arguments.
Arguments delimited by double quotes (") are considered a single argument even if it has spaces or newlines
The \" escape sequence may be used to insert a literal double quote in an argument
Unicode characters are allowed (assuming UTF8 is safe).
What I've tried
I've looked into regular expressions, but it got very complicated, very fast. I've looked into StringTokenizer (Which appears very primitive) and StreamTokenizer (Which doesn't handle unicode very well).
I would like to avoid writing a parser by hand if possible.
Any ideas with regards to this? My latest attempt is as follows:
public static List<String> tokenize(String s) {
List<String> opts = new ArrayList<>();
try (StringReader sr = new StringReader(s)) {
StreamTokenizer st = new StreamTokenizer(sr);
st.resetSyntax();
// From ! to end of ascii range. But alas, no unicode
st.wordChars(31, 127);
st.quoteChar('\"');
st.whitespaceChars(32, 32);
while (st.nextToken() != StreamTokenizer.TT_EOF) {
opts.add(st.sval);
}
} catch (IOException e) {}
return opts;
}
You can try with opencsv library, imported using gradle like:
compile 'net.sf.opencsv:opencsv:3.4'
Try something similar to following program:
import com.opencsv.CSVReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
private static final char SEPARATOR = ' ';
private static final char QUOTE_CHAR = '"';
private static final char ESCAPE = '\\';
public static void main(String[] args) throws IOException {
List<String[]> result = new ArrayList<>();
CSVReader reader = new CSVReader(
new FileReader(args[0]),
SEPARATOR,
QUOTE_CHAR,
ESCAPE);
result.addAll(reader.readAll());
for (int i = 0; i < result.size(); i++) {
System.out.println(Arrays.toString(result.get(i)));
}
}
}
That yields:
[client-properties, create, mode, publisher, version, mode]
[client-properties, set, publisher, version, mode, prop1, value
value
value]
[client-properties, set, publisher, version, mo"de, prop2, שלום עליכם]
I am novice to java however, I cannot seem to figure this one out. I have a CSV file in the following format:
String1,String2
String1,String2
String1,String2
String1,String2
Each line are pairs. The 2nd line is a new record, same with the 3rd. In the real word the CSV file will change in size, sometimes it will be 3 records, or 4, or even 10.
My issues is how do I read the values into an array and dynamically adjust the size? I would imagine, first we would have to parse though the csv file, get the number of records/elements, then create the array based on that size, then go though the CSV again and store it in the array.
I'm just not sure how to accomplish this.
Any help would be appreciated.
You can use ArrayList instead of Array. An ArrayList is a dynamic array. ex.
Scanner scan = new Scanner(new File("yourfile"));
ArrayList<String[]> records = new ArrayList<String[]>();
String[] record = new String[2];
while(scan.hasNext())
{
record = scan.nextLine().split(",");
records.add(record);
}
//now records has your records.
//here is a way to loop through the records (process)
for(String[] temp : records)
{
for(String temp1 : temp)
{
System.out.print(temp1 + " ");
}
System.out.print("\n");
}
Just replace "yourfile" with the absolute path to your file.
You could do something like this.
More traditional for loop for processing the data if you don't like the first example:
for(int i = 0; i < records.size(); i++)
{
for(int j = 0; j < records.get(i).length; j++)
{
System.out.print(records.get(i)[j] + " ");
}
System.out.print("\n");
}
Both for loops are doing the same thing though.
You can simply read the CSV into a 2-dimensional array just in 2 lines with the open source library uniVocity-parsers.
Refer to the following code as an example:
public static void main(String[] args) throws FileNotFoundException {
/**
* ---------------------------------------
* Read CSV rows into 2-dimensional array
* ---------------------------------------
*/
// 1st, creates a CSV parser with the configs
CsvParser parser = new CsvParser(new CsvParserSettings());
// 2nd, parses all rows from the CSV file into a 2-dimensional array
List<String[]> resolvedData = parser.parseAll(new FileReader("/examples/example.csv"));
// 3rd, process the 2-dimensional array with business logic
// ......
}
tl;dr
Use the Java Collections rather than arrays, specifically a List or Set, to auto-expand as you add items.
Define a class to hold your data read from CSV, instantiating an object for each row read.
Use the Apache Commons CSV library to help with the chore of reading/writing CSV files.
Class to hold data
Define a class to hold the data of each row being read from your CSV. Let's use Person class with a given name and surname, to be more concrete than the example in your Question.
In Java 16 and later, more briefly define the class as a record.
record Person ( String givenName , String surname ) {}
In older Java, define a conventional class.
package work.basil.example;
public class Person {
public String givenName, surname;
public Person ( String givenName , String surname ) {
this.givenName = givenName;
this.surname = surname;
}
#Override
public String toString ( ) {
return "Person{ " +
"givenName='" + givenName + '\'' +
" | surname='" + surname + '\'' +
" }";
}
}
Collections, not arrays
Using the Java Collections is generally better than using mere arrays. The collections are more flexible and more powerful. See Oracle Tutorial.
Here we will use the List interface to collect each Person object instantiated from data read in from the CSV file. We use the concrete ArrayList implementation of List which uses arrays in the background. The important part here, related to your Question, is that you can add objects to a List without worrying about resizing. The List implementation is responsible for any needed resizing.
If you happen to know the approximate size of your list to be populated, you can supply an optional initial capacity as a hint when creating the List.
Apache Commons CSV
The Apache Commons CSV library does a nice job of reading and writing several variants of CSV and Tab-delimited formats.
Example app
Here is an example app, in a single PersoIo.java file. The Io is short for input-output.
Example data.
GivenName,Surname
Alice,Albert
Bob,Babin
Charlie,Comtois
Darlene,Deschamps
Source code.
package work.basil.example;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class PersonIo {
public static void main ( String[] args ) {
PersonIo app = new PersonIo();
app.doIt();
}
private void doIt ( ) {
Path path = Paths.get( "/Users/basilbourque/people.csv" );
List < Person > people = this.read( path );
System.out.println( "People: \n" + people );
}
private List < Person > read ( final Path path ) {
Objects.requireNonNull( path );
if ( Files.notExists( path ) ) {
System.out.println( "ERROR - no file found for path: " + path + ". Message # de1f0be7-901f-4b57-85ae-3eecac66c8f6." );
}
List < Person > people = List.of(); // Default to empty list.
try {
// Hold data read from file.
int initialCapacity = ( int ) Files.lines( path ).count();
people = new ArrayList <>( initialCapacity );
// Read CSV file.
BufferedReader reader = Files.newBufferedReader( path );
Iterable < CSVRecord > records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse( reader );
for ( CSVRecord record : records ) {
// GivenName,Surname
// Alice,Albert
// Bob,Babin
// Charlie,Comtois
// Darlene,Deschamps
String givenName = record.get( "GivenName" );
String surname = record.get( "Surname" );
// Use read data to instantiate.
Person p = new Person( givenName , surname );
// Collect
people.add( p ); // For real work, you would define a class to hold these values.
}
} catch ( IOException e ) {
e.printStackTrace();
}
return people;
}
}
When run.
People:
[Person{ givenName='Alice' | surname='Albert' }, Person{ givenName='Bob' | surname='Babin' }, Person{ givenName='Charlie' | surname='Comtois' }, Person{ givenName='Darlene' | surname='Deschamps' }]
{"smscresponse":{"calluid":"3333","to":"0000","event":"ABC"}}
I am using
split("{")[1] to get "calluid":"3333","to":"0000","event":"ABC"
But i am getting
Illegal repetition
{ error.
What i want is calluid .How i can get that one.
Thanks in advance...
You could escape the { character, something like...
String text = "{\"smscresponse\":
{\"calluid\":\"3333\",\"to\":\"0000\",\"event\":\"ABC\"}}";
String[] split = text.split("\\{");
System.out.println(split.length);
System.out.println(split[2]);
Which outputs...
3
"calluid":"3333","to":"0000","event":"ABC"}}
To get "3333", you could do something like...
split = split[2].split(":|,"); // Split on : or ,
System.out.println(split[1]);
Which outputs
"3333"
Now, if you really wanted to be clever, you could try something like...
String[] split = text.split("\\{|:|,|\\}");
for (String part : split) {
System.out.println(part);
}
Which outputs
// Note, this is an empty line
"smscresponse"
// Note, this is an empty line
"calluid"
"3333"
"to"
"0000"
"event"
"ABC"
Updated...
A slightly better solution might be...
Pattern p = Pattern.compile("\"([^\"]*)\"");
Matcher m = p.matcher(text);
while (m.find()) {
System.out.println(m.group());
}
Which outputs
"smscresponse"
"calluid"
"3333"
"to"
"0000"
"event"
"ABC"
Try to split using input.split("[{]");
String abc = "{\"smscresponse\":{\"calluid\":\"3333\",\"to\":\"0000\",\"event\":\"ABC\"}}";
String[] splittedValue = abc.split("[{]");
for(String value : splittedValue)
System.out.println(""+value);
String s = "{\"smscresponse\":{\"calluid\":\"3333\",\"to\":\"0000\",\"event\":\"ABC\"}}";
System.out.println(s.split("\\{")[2].split("}")[0]);
Don't worry about "\". This will work for your dynamically generated data.
EDIT : This will get you "calluid"
System.out.println(s.split("\\{")[2].split("}")[0].split(",")[0]);
Create a JSON object of the given string and parse the JSON object to fetch the value. Use the library org.json
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonSimpleExample {
public static void main(String[] args) {
JSONParser parser = new JSONParser();
try {
JSONObject jsonObj = new JSONObject("{\"smscresponse\":{\"calluid\":\"3333\",\"to\":\"0000\",\"event\":\"ABC\"}}");
String calluid = (String) jsonObject.get("smscresponse").getString("calluid");
System.out.println(calluid);
} catch (ParseException e) {
e.printStackTrace();
}
}
}