Relatively new to programming here so I apologize if this is rather basic.
I am trying to convert string lines into actual variables of different types.
My input is a file in the following format:
double d1, d2 = 3.14, d3;
int a, b = 17, c, g;
global int gInt = 1;
final int fInt = 2;
String s1, s2 = "Still with me?", s3;
These lines are all strings at this point. I wish to extract the variables from the strings and receive the actual variables so I can use and manipulate them.
So far I've tried using regex but I'm stumbling here. Would love some direction as to how this is possible.
I thought of making a general type format for example:
public class IntType{
boolean finalFlag;
boolean globalFlag;
String variableName;
IntType(String variableName, boolean finalFlag, boolean globalFlag){
this.finalflag = finalFlag;
this.globalFlag = globalFlag;
this.variableName = variableName;
}
}
Creating a new wrapper for each of the variable types.
By using and manipulating I would like to then compare between the wrappers I've created and check for duplicate declarations etc'.
But I don't know if I'm on the right path.
Note: Disregard bad format (i.e. no ";" at the end and so on)
While others said that this is not possible, it actually is. However it goes somewhat deep into Java. Just search for java dynamic classloading. For example here:
Method to dynamically load java class files
It allows you do dynamically load a java file at runtime. However your current input does not look like a java file but it can easily be converted to one by wrapping it with a small wrapper class like:
public class CodeWrapper() {
// Insert code from file here
}
You can do this with easy file or text manipulations before loading the ressource as class.
After you have loaded the class you can access its variables via reflection, for example by
Field[] fields = myClassObject.getClass().getFields();
This allows you to access the visibility modifier, the type of the variable, the name, the content and more.
Of course this approach presumes that your code actually is valid java code.
If it is not and you are trying to confirm if it is, you can try to load it. If it fails, it was non-valid.
I have no experience with Java, but as far as my knowledge serves me, it is not possible to actually create variables using a file in any language. You'll want to create some sort of list object which can hold a variable amount of items of a certain type. Then you can read the values from a file, parse them to the type you want it to be, and then save it to the list of the corresponding type.
EDIT:
If I were you, I would change my file layout if possible. It would then look something like this:
1 2 3 4 //1 int, 2 floats, 3 booleans and 4 strings
53
3.14
2.8272
true
false
false
#etc.
In pseudo code, you would then read it as follows:
string[] input = file.Readline().split(' '); // Read the first line and split on the space character
int[] integers = new int[int.Parse(input[0])] // initialise an array with specefied elements
// Make an array for floats and booleans and strings the same way
while(not file.eof) // While you have not reached the end of the file
{
integers.insert(int.Parse(file.ReadLine())) // parse your values according to the size which was given on the first line of the file
}
If you can not change the file layout, then you'll have to do some smart string splitting to extract the values from the file and then create some sort of dynamic array which resizes as you add more values to it.
MORE EDITS:
Based on your comment:
You'll want to split on the '=' character first. From the first half of the split, you'll want to search for a type and from the second half, you can split again on the ',' to find all the values.
I am writing a program that takes in a file and extracts data from a single string within the file. I run into a problem when I try to separate the substrings in the way that I want. The goal is to separate the larger chunks of the line from other large chunks without separating the smaller chunks within the larger chunk (separated by commas).
An example of the file contents would be this: (Although it is slightly long, the files I have may vary from short lists like this to 50 or even to 100 blocks of item sets)
{"timeStamp":1477474644345,"itemSets":[{"mode":"any","sortrank":4999,"type":"custom","priority":false,"isGlobalForMaps":true,"uid":"LOL_D957E9EC-39E4-943E-C55E-52B63E05D99C","isGlobalForChampions":false,"associatedMaps":[],"associatedChampions":[40],"blocks":[{"type":"starting","items":[{"id":"3303","count":1},{"id":"2031","count":1},{"id":"1082","count":1},{"id":"3340","count":1},{"id":"3363","count":1},{"id":"2043","count":1},{"id":"3364","count":1}]},{"type":"Support Build Items","items":[{"id":"2049","count":1},{"id":"1001","count":1},{"id":"3165","count":1},{"id":"3117","count":1},{"id":"2301","count":1},{"id":"3089","count":1},{"id":"3135","count":1},{"id":"3504","count":1}]},{"type":"AP Build Items","items":[{"id":"3165","count":1},{"id":"3020","count":1},{"id":"3089","count":1},{"id":"3135","count":1},{"id":"3285","count":1},{"id":"3116","count":1}]},{"type":"Other Items (Situational Items)","items":[{"id":"3026","count":1},{"id":"3285","count":1},{"id":"3174","count":1},{"id":"3001","count":1},{"id":"3504","count":1}]}],"title":"Janna Items","map":"any"},{"mode":"any","sortrank":0,"type":"custom","priority":false,"isGlobalForMaps":false,"uid":"LOL_F265D25A-EA44-5B86-E37A-C91BD73ACB4F","isGlobalForChampions":true,"associatedMaps":[10],"associatedChampions":[],"blocks":[{"type":"Searching","items":[{"id":"3508","count":1},{"id":"3031","count":1},{"id":"3124","count":1},{"id":"3072","count":1},{"id":"3078","count":1},{"id":"3089","count":1}]}],"title":"TEST","map":"any"}]}
The code I have attempted to write tries to separate this into meaningful chunks, here is what I have written so far:
cutString = dataFromFile.substring(dataFromFile.indexOf("itemSets\":") + 11, dataFromFile.indexOf("},{"));
stringContinue = dataFromFile.substring(cutString.length());
while(stringContinue.contains("},{"))
{
//Do string manipulation to cut every part and re-attach it, then re-check to find if this ("},{\"id") is not there
if(stringContinue.contains("},{\"id"))
{
//if(stringContinue.equals(anObject))
cutString = cutString + stringContinue.substring(0, stringContinue.indexOf("},{\"id"));
}
else if(stringContinue.contains("},{\"count"))
{
cutString = cutString + stringContinue.substring(0, stringContinue.indexOf("},{\"count"));
}
else if(stringContinue.contains("},{"))
{
cutString = cutString + stringContinue.substring(0, stringContinue.indexOf("},{"));
}
stringContinue = stringContinue.substring(cutString.length());
//Check if we see a string pattern that is the cut off point
//if()
//System.out.println(stringContinue);
System.out.println(cutString);
}
But when I run it, I get an output like this:
{"mode":"any","sortrank":4999,"type":"custom","priority":false,"isGlobalForMaps":true,"uid":"LOL_D957E9EC-39E4-943E-C55E-52B63E05D99C","isGlobalForChampions":false,"associatedMaps":[],"associatedChampions":[40],"blocks":[{"type":"starting","items":[{"id":"3303","count":1arting","items":[{"id":"3303","count":1
The output I want to achieve is this:
{"mode":"any","sortrank":4999,"type":"custom","priority":false,"isGlobalForMaps":true,"uid":"LOL_D957E9EC-39E4-943E-C55E-52B63E05D99C","isGlobalForChampions":false,"associatedMaps":[],"associatedChampions":[40],"blocks":[{"type":"starting","items":[{"id":"3303","count":1},{"id":"2031","count":1},{"id":"1082","count":1},{"id":"3340","count":1},{"id":"3363","count":1},{"id":"2043","count":1},{"id":"3364","count":1}]},{"type":"Support Build Items","items":[{"id":"2049","count":1},{"id":"1001","count":1},{"id":"3165","count":1},{"id":"3117","count":1},{"id":"2301","count":1},{"id":"3089","count":1},{"id":"3135","count":1},{"id":"3504","count":1}]},{"type":"AP Build Items","items":[{"id":"3165","count":1},{"id":"3020","count":1},{"id":"3089","count":1},{"id":"3135","count":1},{"id":"3285","count":1},{"id":"3116","count":1}]},{"type":"Other Items (Situational Items)","items":[{"id":"3026","count":1},{"id":"3285","count":1},{"id":"3174","count":1},{"id":"3001","count":1},{"id":"3504","count":1}]}],"title":"Janna Items","map":"any"}
{"mode":"any","sortrank":0,"type":"custom","priority":false,"isGlobalForMaps":false,"uid":"LOL_F265D25A-EA44-5B86-E37A-C91BD73ACB4F","isGlobalForChampions":true,"associatedMaps":[10],"associatedChampions":[],"blocks":[{"type":"Searching","items":[{"id":"3508","count":1},{"id":"3031","count":1},{"id":"3124","count":1},{"id":"3072","count":1},{"id":"3078","count":1},{"id":"3089","count":1}]}],"title":"TEST","map":"any"}
So then my question is how do I check for the point where I can separate the blocks without getting java to detect the same pattern that it uses to separate the smaller chunks? Basically I am looking for a pattern like this ("},{"), but not this ("},{\"id:") or this ("},{\count:"). Is there any other things that the String Class can offer for functionality that is similar that i am not aware of?
Edit: Although using a json parser would make things easier and convenient for this type of problem, another one rises because it would make the program only take in json files. This question is more for string manipulation and trying to find a part of the string that can separate the large blocks of information without touching or changing (very minimally as possible) the smaller blocks that have the same way of separation. So far regex and splitting strings to be re-attached later seems to be the way to go unless there is a more clear-cut answer.
You could split the string into an array based on regex like this:
//fileString is the String you get from your file
String[] chunksIWant = fileString.split("\\},\\{");
This will return the String array chunksIWant split in the chunks you want. It does get rid of the regex itself, in this case "},{", so if you would need the symbols for some reason you will have to add them back afterwards.
You are getting this data from file in Json format.
So when you get that data on java side use JsonParser to convert data in JsonArray format.
Then you can iterate that JsonArray to get as JsonObject by using String name.
You can use value of JsonObject as required.
I might just be doing something stupid here but I'm trying to write a program that will take all the text from an xml file, put it in an arraylist as strings, then find certain recurring strings and count them. It basically works, but for some reason it won't go through the entire xml file. It's a pretty large file with over 15000 lines (ideally I'd like it to be able to hand any amount of lines though). I did a test to output everything it was putting in the arraylist to a .txt file and eventually the last line simply says "no", and there's still much more text/lines to go through.
This is the code I'm using to make the arraylist (lines is the amount of lines in the file):
// make array of strings
for (int i=0; i<lines; i++) {
strList.add(fin2.next());
}
fin2.close();
Then I'm searching for the desired strings with:
// find strings
for (String string : strList) {
if(string.matches(identifier)){
count++;
}
}
System.out.println(count);
fout.println(count);
It basically works (the printwriter and scanners work, line count works, etc) except the arraylist won't take all the text from the .xml file, so of course the count at the end is inaccurate. Is arraylist not the best solution for this problem?
This is a BAD practice to do. Each time you put a string into an ArrayList and keep it there, you're going to have an increase in memory usage. The bigger the file, the more memory is used up to the point where you're wondering why your application is using 75% of your memory.
You don't need to store the lines into an ArrayList in order to see if they match. You can simply just read the line and compare it to whatever text you're comparing it to.
Here would be your code modified:
String nextString = "";
while (fin2.hasNext()) {
nextString = fin2.next();
if (nextString.matches(identifier) || nextString.matches(identifier2)) {
count++;
}
}
fin2.close();
System.out.pritnln(count);
Eliminates looping through everything twice, saves you a ton of memory, and gives you accurate results. Also I'm not sure if you're meaning to read the entire line, or you have some sort of token. If you want to read the entire line, change hasNext to hasNextLine and next to nextLine
Edit: Modified the code to show what it would look like looking for multiple strings.
Have you tried to use map, like HashMap. Since Your goal is to find the occurrence of word from a xml, hashmap will make your like easier.
The problem is not with your ArrayList but with your for loop. What's happening is that you're using the number of lines in your file as your sentinel value, but rather than incrementing i by 1 every line, you are doing it every word. Therefore, not all the words are added to your ArrayList because your loop terminates earlier than expected. Hope this helps!
EDIT: I don't know what object you are using right now to collect the contents of this xml file, but I would suggest using Scanner instead (passing the File as a parameter in the constructor) and replacing the current for loop with a while loop that uses while (nameOfScanner.hasNextLine())
I'm writing a personal program that will help my Dnd group and at the same time expand my java knowledge a little :) now part of that involves some arrays, and loading text into them from a text file. Now I have succeeded in that and with them all set statically it's all fine, since the end result will have lots of arrays I thought rather than making each array do all the leg work itself I would create an array handler method.
So I would do filetest(filename,arrayName) (ie filetest(table1,table1Array)
and it would make the array, but I'm stuck on one thing: How do I make the array using the name from arrayName?
It's pretty much got me stumped my so far failed code is:
public class arrayFileHandler {
public static void fileTest(String fileName,String arrayName) throws FileNotFoundException{
int a = 0;
System.out.println("test");
System.out.println(System.getProperty("user.dir")); //this is the folder where the file SHOULD be
Scanner testTable1 = new Scanner(new File("data/"+fileName+".txt")); //with luck this will load the file ! if i understand + correct!
//Scanner testTable1 = new Scanner(new File("C:/Dev/newjava/dnd/src/dnd/test.txt")); //this works but is no good for our needs
ArrayList<String> testTable = new ArrayList<String>(); //create the array list since at this stage we dont know how long the array will be
while(testTable1.hasNextLine()){ //see if the file we are using has a next line (could cause me issues if the txt has blank lines...hmmm)
String line = testTable1.nextLine(); //put that line into the string "line"
testTable.add(line); //add that line to the array list
System.out.println(line); //lets see what that line says
a++; //to help count the lines(not needed now)
speechHandler.speechSynth(2, 1, 0, 60, line); //a debug line
}
System.out.println("there are "+ a +" lines"); //print how many lines there are
String arrayName[] = new String [testTable.size()]; //create an array with the number of "slots" equal to the number of slots in the arraylist and named with the String in arrayName
arrayName = testTable.toArray(arrayName);//copy the arraylist to the array
System.out.println(arrayName[0]);
//System.out.println(tableList[2]);
speechHandler.speechSynth(2, 1, 0, 60, arrayName[2]); //also a debug line
}
Now the important line is String arrayName[] = new String [testTable.size()]; it's trying to create an array called arrayName, but I need it to be created with whatever name is in the string called arrayName, so in my example in the second paragraph it would be called table1Array.
Googling hasn't helped me much and I'm wondering if what I want to do is actually possible.
It's not possible and it also doesn't make any sense in your case. What's your goal? You're just creating a local variable, it doesn't matter which name did you choose. It'd only get complicated, because you'd need to access it using another variable (containing the name). I really don't see any usage in this.
If you were using some dynamic interpreted language, it could be done by using something like "eval", which would create variable with defined name at runtime. But in the Java, all code (including all variables etc) is compiled into bytecode and then executed. Do you see the problem? At compile time, the variable might not be recognized (because of missing name), and therefore it's not possible. Truth is, that bytecode doesn't contain local variable's names, but why JVM would have to solve issues like "isn't there already a variable with such a name" and so on? Bytecode would only get bigger, without actually bringing some new functionality.
If you really need this for some reason (and I just can't imagine which is that), I'd suggest you to use some sort of associative array, e.g. java.lang.Hashtable<>. It allows you to change names runtime.
From you last comment, if I understand right, you want to create arrays of strings based on the contents of text files.
You started with reading the lines into an ArrayList of Strings. I suggest you stick with ArrayLists, and not bother with arrays.
If you are going to read lots of files, I suggest you put your code which creates the ArrayLists into a method so you can call it as many times as you want, once for each file.
Below is such a function, copied from your code and modified where necessary (I removed the comments):
Here goes:
public List<String> getLinesFromFile(String filename) {
Scanner testTable1 = new Scanner(new File(filename));
List<String> testTable = new ArrayList<String>();
while(testTable1.hasNextLine()){
String line = testTable1.nextLine();
testTable.add(line);
}
return testTable;
}
You can call that as many times as you like. If you have lots of files, you can 'name' them the same as your filename by storing them in a Map:
First, create a Map whose keys are Strings (so we can look up by filename) and whose values are List (lists of strings - the content of the files)
Map<String, List<String>> fileContentMap = new HashMap<String, List<String>>();
Next, every time we read a file, add it to the Map:
String filename = // ... whatever file to read next
fileContentMap.put(filename, getLinesFromFile(filename));
Finally, when you want to retrieve them:
//retrieve lines from a file I read earlier:
List<String> lines = fileContentMap.get(filename);