what is the best way to parse this string in java? - java

what is the best way to parse this string in java ?
Admin State State Type Interface Name
-------------------------------------------------------------------------
Enabled Connected Dedicated Local Area Connection
Enabled Connected Dedicated Local Area Connection 2
between each word is space, not tab, not any thing else, as you can see number of space is not equal, and also between the word such as "local area connection" is space.
actually i want the name of all of my network interface and the state of them.
this is the output of "netsh" command in windows. (if you know other command witch can get me this info as key:value, it will be helpfull. or may be there is a argument for this command to format it?)
if i can get something like this it will help alot :
Interface Name : Local Area Connection
Type : Dedicated
State : Connected
Admin State : Enabled
Interface Name : Local Area Connection 2
Type : Dedicated
State : Connected
Admin State : Enabled

BufferedReader b = new BufferedReader(new StringReader(myString));
String line;
while (!(line = b.readLine()).startsWith("-----")) {/*skip*/};
while ((line = b.readLine()) != null) {
if (line.trim().equals("")) continue; // skip blank lines
String[] splat = line.split(" +",4);
System.out.println("Interface Name : " + splat[3]);
System.out.println("Type : " + splat[2]);
System.out.println("State : " + splat[1]);
System.out.println("Admin State : " + splat[0]);
}
b.close();

You should use Java capabilities to get the network interfaces. The class NetworkInterface provides what you are looking for.
You can find an example here: Listing Network Interface Addresses

If the columns are of known width, use String.substring(..) to get each column & trim() the result.

If there's no column separator:
1 - It seems to be fixed size fields. This means the columns will always have X caracters, and next column will always start at X+1. In your exemple, "Admin State" will always have 15 characters and "State" will always begin on 16th character. "State" has also 15 characters [...]
2 - If fixed size fields don't work, you can try to parse by 2 spaces, but its way prone to errors

If you know the positions, you can do like
String state = line.substring(15, 30).trim();
If you don't know, then parse the first line for the known headers (like line.indexOf("State")), that will tell you the positions.
// for the header line
int stateBegin = line.indexOf("State");
int typeBegin = line.indexOf("Type");
// for all other lines
String state = line.substring(stateBegin, typeBegin).trim();

String s ="Admin State State Type Interface Name";
String[] str = s.split(" +");
for(String ss: str)
System.out.println(ss);
Try above code to split String with more than one space.
Output:
Admin State
State
Type
Interface Name

Related

Reading/splitting different parts from different lines in a text file in Java

I'm working on this assignment I'm supposed to read from a text file like this...
Student Name: John
Student ID: 12344/19
College: Science
Credits Attempted: 15
Credits Earned: 15
Grade Points: 41.2
Course Code Course Title Credit Grade
COMP1007, Amazing Applications of AI, 2, B
COMP2202, Fund. of Object Oriented Prog., 3, C-
MATH2108, Calculus (2), 3, C-
MATH3340, Discrete Math. for Comp. Sci., 3, B-
STAT2101, Introduction to Statistics, 4, C+
I should read this text file and calculate the GPA of the student and create an output file that should look like this...
Output text file
So basically I'm stuck and I have no idea what I to do...
I know how to read line by line and split a line into different parts, but this doesn't seem to work here since every line is different from the other. For example the first line has two parts, the "Student Name" and the name itself in this case "John". But in line 9, there are four different parts, the course code, course name, credit and grade.
I'm honestly not looking to cheat on the assignment but only to understand it
help :)
Note I can't use Stream or Hashmap or BufferedReader
Each data record in a text file always has a Start and an End. The easiest records are obviously those that are contained on a single delimited line within the text file, where each file line is in fact a record as you can see within a typical CSV format data file. The harder records to read are the Multi-Line records whereas each data record consists of several sequential text file lines but still, there is a Start and a End to each record.
The Start of a record is usually pretty easy to distinguish. For example, in the file example you provided in your post it is obviously any file line that starts with Student Name:.
The End of a record may not always be so easy to determine since many applications do not save fields which contain no data value in order to help increase access speed and reduce file bloat. The thought is "why have a text file full of empty fields" and to be honest, rightly so. I'm not a big fan of text file records anyways since utilizing a database would make far better sense for larger amounts of data. In any case, there will always be a file line that will indicate the Start of a record so it would make sense to read from Start to Start of the next record or in the case of the last record in file, from Start to End Of File (EOF).
Here is an example (read the comments in code):
// System line separator to use in files.
String ls = System.lineSeparator();
/* Array will hold student data: Student Name, Student ID, College,
Credits Attempted, Credits Earned, and finally Grade Points. */
String[] studentData = new String[6];
// String Array to hold Course Table Header Names.
String[] coursesHeader = {"COURSE NO", "COURSE TITLE", "CREDITS", "GRADE"};
// List Interface to hold all the course Data line Arrays for each record
java.util.List<String[]> cousesList = new java.util.ArrayList<>();
// Underlines to be used for Console display and file records
// Under courses Header
String underline1 = "-------------------------------------------------------------";
// Under all the courses
String underline2 = "------------------------------------------------------------------------------------";
/* Read and Write to files using 'Try With Resources' so to
automatically close the reader an writer objects. */
try (Scanner reader = new Scanner(new java.io.File("StudentData.txt"), "UTF-8");
java.io.Writer writer = new java.io.FileWriter("StudentsGPA.txt")) {
// For console display only! [Anything (except caught errors) to Console can be deleted]
System.out.println("The 'StudentsGPA.txt' file will contain:");
System.out.println("======================================");
System.out.println();
// Will hold each line read from the reader
String line = "";
/* Will hold the name for the next record. This would be the record START
but only AFTER the first record has been read. */
String newName = "";
// Start reading the 'StudentData.txt' file (line by line)...
while (reader.hasNextLine()) {
/* If newName is empty then we're on our first record or
there is only one record in file. */
if (newName.isEmpty()) {
line = reader.nextLine(); // read in a file line...
}
else {
/* newName contains a name so we must have bumped into
the START of a new record during processing of the
previous record. We aleady now have the first line
of this new record (which is the student's name line)
currently held in the 'newName' variable so we just
make 'line' equal what is in the 'newName' variable
and carry on processing the data as normal. in essance,
we simply skipped a read because we've already read it
earlier when processing the previous record. */
line = newName;
// Clear this variable in preparation for another record START.
newName = "";
}
/* Skip comment lines (lines that start with a semicolon (;)
or a hash mark (#). Also skip any blank lines. */
if (line.startsWith(";") || line.startsWith("#") || line.isEmpty()) {
continue;
}
/* Does this file line start with 'Student Name:'? If so then
this is a record START, let's process this record. If not
then just keep reading the file. */
if (line.startsWith("Student Name:")) {
/* Let's put the student name into the studentData array at
index 0. If it is detected that there has been no name
applied for some reason then we place "N/A" as the name.
We use a Ternary Operator for this. So, "N/A" will be a
Default if there is not name. This will be typical for
the other portions of student data. */
studentData[0] = line.isEmpty() ? "N/A" : line.split("\\s*:\\s*")[1].trim();
/* Let's keep reading the file from this point on and retrieve
the other bits of student data to fill the studentData[]
Array... */
for (int i = 1; i < 6; i++) {
line = reader.nextLine().trim();
/* If we encounter a comment line or a blank line then let's
just skip past it. We don't want these. */
if (line.startsWith(";") || line.startsWith("#") || line.isEmpty()) {
i--;
continue;
}
/* Store the other portions of student data into the
studentData Array using "N/A" as a default should
any student data field contain nothing. */
studentData[i] = line.isEmpty() ? "N/A" : line.split("\\s*:\\s*")[1].trim();
}
// The current Student's Courses...
/* Clear the List Interface object in preparation for new
Courses from this particular record. */
cousesList.clear();
// Read past the courses header line...We don't want it.
reader.nextLine();
// Get the courses data (line by line)...
while (reader.hasNextLine()) {
line = reader.nextLine().trim();
/* Again, if we encounter a comment line or a blank line
in this section then let's just skip past it. We don't
want these. */
if (line.startsWith(";") || line.startsWith("#") || line.isEmpty()) {
continue;
}
/* At this point, if we have read in a line that starts
with 'Student Name:' then we just hit the START of a
NEW Record! This then means that the record we're
currently working on is now finished. Let's store this
file line into the 'newRecord' variable and then break
out of this current record read. */
if (line.startsWith("Student Name:")) {
newName = line;
break;
}
/* Well, we haven't reached the START of a New Record yet
so let's keep creating the courses list (line by line).
Break the read in course line into a String[] array.
We use the String#split() method for this with a small
Regular Expression (regex) to split each line based on
comma delimiters no matter how the delimiter spacing
might be (ex: "," " ," " , " or even " , "). */
String[] coursesData = line.split("\\s*,\\s*");
/* Add this above newly created coursesData string array
to the list. */
cousesList.add(coursesData);
}
/* Write (append) this current record to new file. The String#format()
method is used here to save the desired data into the 'StudentGPA.txt'
file in a table style format. */
// Student Data...
writer.append(String.format("%-12s: %-25s", "ID", studentData[1])).append(ls);
writer.append(String.format("%-12s: %-25s", "Name", studentData[0])).append(ls);
writer.append(String.format("%-12s: %-25s", "College", studentData[2])).append(ls);
// Student Courses...
// The Header line
writer.append(String.format("%-13s %-30s %-10s %-4s", coursesHeader[0],
coursesHeader[1], coursesHeader[2], coursesHeader[3])).append(ls);
// Apply an Underline (underline1) under the header.
writer.append(underline1).append(ls);
// Write the Courses data in a table style format to make the Header format.
for (String[] cData : cousesList) {
writer.append(String.format("%-13s %-33s %-9s %-4s",
cData[0], cData[1], cData[2], cData[3])).append(ls);
}
// Apply an Underline (underline2) under the Courses table.
writer.append(underline2).append(ls);
// Display In Console Window (you can delete this if you want)...
System.out.println(String.format("%-12s: %-25s", "ID", studentData[1]));
System.out.println(String.format("%-12s: %-25s", "Name", studentData[0]));
System.out.println(String.format("%-12s: %-25s", "College", studentData[2]));
System.out.println(String.format("%-13s %-30s %-10s %-4s", coursesHeader[0],
coursesHeader[1], coursesHeader[2], coursesHeader[3]));
System.out.println(underline1);
for (String[] cData : cousesList) {
System.out.println(String.format("%-13s %-33s %-9s %-4s",
cData[0], cData[1], cData[2], cData[3]));
}
System.out.println(underline2);
// The LAST line of each record, the Credits...
// YOU DO THE CALCULATIONS FOR: totalAttemped, semGPA, and cumGPA
String creditsAttempted = studentData[3];
String creditsEarned = studentData[4];
int credAttempted = 0;
int credEarned = 0;
int totalAttempted = 0;
double semGPA = 0.0d;
double cumGPA = 0.0d;
/* Make sure the 'credits attemted' numerical value is in fact
a string representaion of an integer value. if it is then
convert that string numerical value to integer. */
if (creditsAttempted.matches("\\d+")) {
credAttempted = Integer.valueOf(creditsAttempted);
}
/* Make sure the 'credits earned' numerical value is in fact
a string representaion of an integer value. if it is then
convert that string numerical value to integer. */
if (creditsEarned.matches("\\d+")) {
credEarned = Integer.valueOf(creditsEarned);
}
// Build the last record line (the Credits string) with the acquired data.
String creditsString = new StringBuilder("CREDITS: TOTAL.ATTEMPTED ")
.append(totalAttempted).append("? EARNED ").append(credEarned)
.append(" ATTEMPTED ").append(credAttempted).append(" SEM GPA ")
.append(semGPA).append("? CUM GPA ").append(cumGPA).append("?")
.toString();
// Display it to the console Window (you can delete this).
System.out.println(creditsString);
System.out.println();
// Write the built 'credit string' to file which finishes this record.
writer.append(creditsString).append(ls);
writer.append(ls); // Blank Line in preparation for next record.
writer.flush(); // Flush the data buffer - write record to disk NOW.
}
}
}
// Trap Errors...Do whatever you want with these.
catch (FileNotFoundException ex) {
System.err.println("File Not Found!\n" + ex.getMessage());
}
catch (IOException ex) {
System.err.println("IO Error Encountered!\n" + ex.getMessage());
}
Yes, it looks long but if you get rid of all the comments you can see that it really isn't. Don't be afraid to experiment with the code. Make it do what you want.
EDIT: (as per comments)
To place the student info portion of each record into an ArrayList so that you can parse it the way you want:
Where the forloop is located within the example code above for gathering the student info, just change this loop to this code and parse the data the way you want:
// Place this ArrayList declaration underneath the 'underline2' variable declaration:
java.util.ArrayList<String> studentInfo = new java.util.ArrayList<>();
then:
if (line.startsWith("Student Name:")) {
studentInfo.clear();
studentInfo.add(line);
/* Let's keep reading the file from this point on and retrieve
the other bits of student data to fill the studentData[]
Array... */
for (int i = 1; i < 6; i++) {
line = reader.nextLine().trim();
/* If we encounter a comment line or a blank line then let's
just skip past it. We don't want these. */
if (line.startsWith(";") || line.startsWith("#") || line.isEmpty()) {
i--;
continue;
}
studentInfo.add(line);
}
// .................................................
// .... The rest of the code for this `if` block ...
// .................................................
}
You will of course need to change the code after this loop to properly represent this ArrayList.
OK, so here's how you do it ...
You read in all of the file and store each line in a List<String>
For the first 8 lines you process each one in a separate way. You can even write a separate function to parse the necessary info out of every line for lines 0-7
All the remaining lines have identical structure. Therefore, you can process them all in the same way to parse out and then process the necessary data.
And a comment to this answer if something is unclear and I'll clarify.

String split from a CSV - Java

I am having a small problem, I hope you can help.
I am reading a CSV in java, in which one of the column has string as follows:
a. "123345"
b. "12345 - 67890"
I want to split this like(Split it into two separate columns):
a. "123345", ""
b. "12345","67890"
Now, when I am using Java's default split function, it splits the string as follows:
a. "123345,"
b. "12345,67890" (Which is basically a string)
Any idea how can I achieve this? I have wasted my 3 hours on this. Hope any one can help.
Code as follows:
while ((line = bufferReader.readLine()) != null)
{
main = line.split("\\,"); //splitting the CSV using ","
//I know that column # 13 is the column where I can find digits like "123-123" etc..
therefore I have hard coded it.
if (main[12].contains("-"))
{
temp = main[12].split("-");
//At this point, when I print temp, it still shows me a string.
//What I have to do is to write them to the csv file.
E.g: ["86409, 3567"] <--Problem here!
}
else
{
//do nothing
}
}
after this, i will write the main[] array to the file.
Please check if java.util.StringTokenizer helps
Example:
StringTokenizer tokenizer = new StringTokenizer(inputString, ";")
Manual: StringTokenizer docs

Getting strings inside a split string

I am loading strings from a text file, eg;
Sunset Blvd 1950.ogg,Sunset Blvd,Paramount Pictures,1950,110,Billy Wilder,4,William Holden,Gloria Swanson,Erich von Stroheim,Nancy Olson
Now I have a class setup that extends from 2 parent classes (Media > Video > Avi/Ogg/etc). And that class holds the following variables;
public Avi(String title, String fileName, int releaseYear, String studio, String director, String castNames, double runtime, int cast) {
super(title, fileName, releaseYear, studio, director, castNames, runtime, cast);
}
Now I load the text file in using a buffer reader and a loop, but heres the problem, the cast names (Which come last in the text file, are also separated with commas but since I am using a splitter already I am not sure how to get every cast member into a simply string such as "Larry Davis,Eddy Murphy,Etc Etc" that can be returned later on. Also using a different splitter for cast names is not an option
if your cast starts at William Holden, you can do
line.split(",", 8);
I assume that by splitter you mean the String method "split".
If so, does your text file always have the same structure ?
Meaning is there always the same number of elements before the cast names ?
Because the String method "split" can take a second parameter specifying the number of elements to retrieve (cf. link to String API)
None of these solutions worked but heres what I came up with that worked:
String castNames = "";
int splitLength = split.length - 7;
for (int i = 0; i < splitLength; i++) {
castNames += split[7 + i] + ",";
}
Avi avi = new Avi(split[1]/*title*/
, split[0]/*filename*/
, Integer.parseInt(split[3])/*releaseyear*/
, split[2]/*studio*/
, split[5]/*director*/
, castNames/*castnames*/
, Double.parseDouble(split[4])/*runtime*/
, Integer.parseInt(split[6])/*cast*/);
return avi;
Having a symbol as the string separator as well as being valid data is not a good idea and results in code that is prone to errors. Of course you can work around that - some people before me have suggested ways to do it - but I strongly recommend that you change your input and remove the ambiguity.

Scanner help - Java

I was looking for a little help as I'm at my wits end on how to accomplish this.
The assignment is to read in a file that contains state names, the governor of that state and the compensation he gets.
Example of the file:
California Tim John $50,000 $78,890 $30,000
North Dakota John Jones $30,000 $40,000 $56,000
Washington Susan K. Bones $30,000 $40,000 $56,000
As you can see, a name can contain more than three words (including the middle initial)
The output I'm supposed to get is the presidents name followed by the total compensation..
Example of output:
Susan K. Bones $126,000
I've already written code that prints out the total compensation. But I'm stuck on reading the names. How do I ignore the state names which can contain at most two words and just take the governor's name?
Here is my code for the total compensation.
Also note: I have to use Scanner on this.
Scanner in = new Scanner(file);
in.nextLine();
do {
double totalCompensation = 0.0;
String readLine = in.nextLine();
readLine = readLine.replaceAll(",", "").replace("$", " ");
String presidentName = "";
Scanner readNumber = new Scanner(readLine);
while(readNumber.hasNext()) {
if (readNumber.hasNextDouble())
totalCompensation += readNumber.nextDouble();
else {
readNumber.next();
}
}
Another note: don't worry, I do have a while(in.hasNextLine()) to close the do loop, later on in my code. I just don't really want to paste in the whole thing.
Any hints would be welcome! Thanks!
If you KNOW ahead of time that you will only ever see US state names, you could have your code look for a state name first. Since you know what part is the state name and what part is the compensation, whatever is left must be the governor's name. There's only 50 states, so this isn't impossibly difficult.
If this is more generic and can be a city/country/whatever and not just a US, there's not a way to distinguish without a better separator character (or quotes to define the "state name" and "governor name".
EDIT: You mention that there is a further requirement that the "leader" name will be of the form "Firstname LastName" "Firstname M. Lastname" or "F. Middlename Lastname". NOW you have enough to solve the answer.
As you pull strings out with the scanner, put them in a list (or if you learned this datatype, a stack is more appropriate). Go through the list backwards. If the 2nd element is an initial, you know the name has three parts. If the 3rd element is an initial, you know the name has three parts. If neither is an initial, you know the name has two parts. Whatever is not the name of the leader is the name of the place.
My previous answer utterly failed to use Scanner, which was a stated requirement. As before, I am using the "New," "North," etc, prefix to delineate two word state names.
static String[] TWO_WORD_STATE_PREFIXES = new String[] {"New", "Rhode", "North", "West", "South"};
public static void scanLine(String line) {
Scanner s = new Scanner(line);
String stateName = s.next();
for (String prefix : TWO_WORD_STATE_PREFIXES)
if (stateName.equals(prefix))
stateName += " " + s.next();
String governorName = "";
String nextToken;
while (!(nextToken = s.next()).startsWith("$"))
governorName += nextToken + " ";
governorName = governorName.trim();
int compensation = 0;
while (s.hasNext())
compensation += Integer.parseInt(s.next().replaceAll("[\\$, ]", ""));
System.out.println(stateName + " - " + governorName + " : " + compensation);
}
public static void main(String[] args) {
scanLine("California Tim John $50,000 $78,890 $30,000");
scanLine("Virginia Some Guy $55,000 $71,890 $30,000");
scanLine("South Carolina Bill F. Gates $91,000 $1,200");
scanLine("Vermont Joan Smith $60,000 $78,890 $30,000");
scanLine("North Dakota Tim John $50,000 $78,890 $30,000");
}
Can the file be modified to contain delimiters other than space like semi-colon. Otherwise one option i can think of is store the list of states and iterate through them and check other wise it would be a name. Eg.
List<String> stateNames={"Alabama","Alaska","Texas"};
This question is about efficient string searching. Let's work on determining which part of the string is the city or state name, since once you have that the rest is trivial.
First, you will need a list of cities and states. Here's a list of cities (should be pretty easy to parse out the actual city names) http://www.census.gov/tiger/tms/gazetteer/places2k.txt and I'm sure you can find a list of states somewhere.
Once you have that, here's a simple strategy for an efficient solution:
put the list of cities and states into a hashtable
split the input string (ex. "Califonia John Doe $213 $1232") by spaces
for each prefix of this list, check if the corresponding string is in the hashtable - if it is, then assume that's the state/city and parse the rest of the input accordingly.
Edit: nevermind - you added some information to the question that makes it much easier to solve. It's no longer an efficient string search problem- it's now a simple puzzle to help you practice looping in Java. See Kane's answer.
It's interesting how drastically just a little bit of information can change the scope of a problem :)

How to read a string with spaces in Java

I am trying to read a user input string which must contain spaces. Right now I'm using:
check = in.nextLine();
position = name.names.indexOf(check);
if (position != -1) {
name.names.get(position);
} else {
System.out.println("Name does not exist");
}
this just returns various errors.
your question isn't very clear - specfically you like like you are checking that what the person has typed matches a known list, not that it does or doesn't have spaces in it, but taking you at your word:
Read the whole line in, then check using
a) Regex
b) indexof() - if your check is very simple
Possibly also want to do a length check on the input line as well (i.e all lines should be < 255 chars or something) , just to be paranoid
If you are doing more like what you code sample looks like then you do something like
ArrayList<String> KnownListOfNames = .....
if(!KnownListOfNames.Contains(UserEnteredString)){
System.out.println("Name not found");
}
Typically you would also do some basic input validation first - google for "SQL injection" if you want to know more.

Categories

Resources