Validating a LaTeX file, java - java

So I have this text file
\begin{document}
{\Large \begin{center} Homework Problems \end{center}}\begin{itemize}\item\end{itemize}
\begin{enumerate}
\begin{proof}
\begin{align}
\end{align}
\end{proof}
\begin{proof}
\begin{align}
\end{align}
\end{proof}
\end{enumerate}
\end{document}
And I want to go through each line, find all of the "\begin" pieces and then take the string with in the "{_}" and store it in a stack. When the corresponding "\end" is found, I call the pop() command on the Stack and remove it. I'm have a few issues though...
I'm running into dealing with all sorts of crazy cases and making sure everything is accommodated and its becoming too specific to this case when I want to make it work for all sorts of files that are written as such.
I don't know how to check for "\begin" and "\end" as opposed to "begin" and "end", the reason this is important is because if the file contains text that says "begins" or "end" it might not be a command and thus, not what I'm looking for.
All "if" statements DO NOT work on account of the "\" being present, I tried adding square brackets but it didn't fix anything.
Here is my code so far, and its getting really confusing, can anyone help organize and help rectify the issues I've stated above?
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Stack;
import java.util.StringTokenizer;
public class LaTeXParser{
public static void main(String args[]) throws FileNotFoundException{
Scanner scan = new Scanner(System.in);
Stack s = new Stack();
int lineCount = 0;
String line;
String nextData = null;
String title = null;
String fname;
System.out.print("Enter the name of the file (no extension): ");
fname = scan.next();
fname = fname + ".txt";
FileInputStream fstream = new FileInputStream(fname);
Scanner fscan = new Scanner(fstream);
System.out.println();
while(fscan.hasNextLine()){
lineCount++;
line = fscan.nextLine();
StringTokenizer tok = new StringTokenizer(line);
while(tok.hasMoreElements()){
nextData = tok.nextToken();
System.out.println("The line: "+nextData);
if(nextData.contains("\\begin") && !nextData.contains("\\end")){
if(nextData.charAt(1) == 'b'){
title = nextData.substring(nextData.indexOf("{") + 1, nextData.indexOf("}"));
s.push(title);
}
else{
//title = nextData.substring();
}
}//end of BEGIN if
if(nextData.contains("\\end") && !nextData.contains("\\begin")){
if(s.peek().equals(nextData.substring(nextData.indexOf("{") + 1, nextData.indexOf("}")))){
s.pop();
}
}//end of END if
if(nextData.contains("\\begin") && nextData.contains("\\end")){
String[] theLine = nextData.split("[{}]");
for(int i = 0 ; i < theLine.length ; i++){
if(theLine[i].equals("\\end") && theLine[i+1].equals(s.peek())){
s.pop();
}
if(theLine[i].equals("\\begin")){
title = theLine[i+1];
s.push(title);
}
}
}//end of BEGIN AND END if
}
}//end of whiles
fscan.close();
while(!s.isEmpty()){
System.out.println("the top "+s.pop());
}
}
}
EDIT: In the if statement that is used to check a line to see if it contains both a "\begin" and "\end" after finding the "\begin", how do I go back through to check if that line also contains it's "\end"? So I am talking about the case...
\begin{itemize}\item\end{itemize}
See I can get to the "\begin" and add the proper string, but it just moves and passes the "\end{itemize}". Anyway to fix this?
Actually it should check and perform normally even after the "itemize" string is pushed, but it doesn't work! I believe it has to do with "\end", can anyone confirm? It skips over that step, and obviously because it doesn't fit the conditions, but it works for the other lines. Just not this specific case!

You probably need to escape the backslashes, so write \\ instead of \. And if they are in regular expressions (regexprs) you need to escape them twice: \\\\ ; I don't think the brackets are needed.

Related

Why does one println statement change the entire output of my code?

Problem
I am currently creating a program to read a file and find a couple of variables. I am running into this problem where changing one println changes the entire output of my code. I have never run into this before and am not sure if this is an eclipse error or my error?
My Code
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class FileAnalyzer {
public static void main(String args[]) throws IOException {
Scanner input = new Scanner(System.in);
String fileName;
int words = 0, letters = 0, blanks = 0, digits = 0, miscChars = 0, lines = 0;
System.out.print("Please enter the file path of a .txt file: ");
fileName = input.nextLine();
File text = new File(fileName);
//System.out.println(text.exists());
Scanner word = new Scanner(text);
while(word.hasNext()) {
//System.out.println(word.next());
words++;
}
word.close();
Scanner letter = new Scanner(text);
while(letter.hasNext()) {
String currentWord = letter.next().toLowerCase();
for(int i = 0; i < currentWord.length(); i++) {
if(Character.isLetter(currentWord.charAt(i))) {
letters++;
}
}
}
letter.close();
Scanner blank = new Scanner(text);
while(blank.hasNextLine()) {
String currentWord = blank.nextLine();
for(int j = 0; j < currentWord.length(); j++) {
if (currentWord.charAt(j) == ' ') {
blanks++;
}
}
}
blank.close();
System.out.println("Words: " + words);
System.out.println("Letters: " + letters);
System.out.println("Blanks: " + blanks);
}
}
However
Simply changingSystem.out.println(word.next()) in the first Scanner instance changes the entire output. If i leave it in I get the three print statements at the bottom and what I am looking for. If I remove it since I do not want each word printed in the file it shows as nothing in the console. Not Sure why one print statement within a while statement changes the entire output.The only reason it was there in the first place was to make sure the scanner was taking input the way I had wanted.
Not Sure why one print statement within a while statement changes the entire output
Because when the statement is present, you're consuming a token from the scanner. When it's commented out, you're not. It's not the printing that consumes the token, it's the call to next().
With it commented out, your loop is:
while (word.hasNext()) {
words++;
}
hasNext() doesn't modify the state of the scanner, so that will just loop forever if it goes into the loop body at all.
If you want to have a line you can comment out or not, change the code to:
while (word.hasNext()) {
String next = word.next(); // Consume the word
System.out.println(next); // Comment this out if you want to
words++;
}
By using System.out.println(word.next()); you are cycling through the elements in a collection due to the next() method. So invoking next() directly will allow you to move through the iteration.
When commenting out //System.out.println(word.next());, then word.hasNext() will cause you to loop forever(provided there is a word) as you will not be able to move to the next token.
The below snippet will help you achieve your desired result
while(word.hasNext()){
word.next();
words++;
}
Not sure why you would want to go thru the text three times. But if you really have to, I would close the first scanner before opening the next.

Palindrome parser logic error

I'm trying to create a program that parses through an input and determines whether or not it is a palindrome. Pasted below is my code so far:
import java.util.Scanner;
//Gets a message and shift amount and caesar shifts the message by the desired amount. Displays the enciphered message.
public class RobustPalChecker{
public static void main(String[] args){
//declare variables
char current, currentReverse;
int msgInt;
String msg, msgReverse;
StringBuffer sbMsg, newMsg;
Scanner sc = new Scanner(System.in);
//get message
System.out.println("Please enter an integer: ");
msg = sc.nextLine().toUpperCase();
//msgReverse = new StringBuffer(msg).reverse().toString();
System.out.println(msg);
//System.out.println("= " + msgReverse);
//get first and last index of string to check if it's a palindrome
for(int i = 0; i < msg.length(); i++) {
current = msg.charAt(i);
if(Character.isLetter(current) == false){
sbMsg = new StringBuffer(msg);
newMsg = sbMsg.deleteCharAt(i);
msgReverse = new StringBuffer(newMsg).reverse().toString();
}
}
if(newMsg.equals(msgReverse)) {
System.out.println("It's a palindrome");
}else {
System.out.println("It's not a palindrome");
}
}
}
Ignore comments as some of them don't apply and I have not cleaned it up yet. The line of code that I'm pretty sure is causing the error is the isLetter line. The goal of that loop is to find any character that is not a letter and just delete it, and that includes whitespace. That last if statement is the one that actually compares the reversed string and regular string. Now the output that the last if statement is giving me when I try to compile is "variable newMsg might not have been initialized" and the same for msgReverse, but that's not my main question.
My main question is: Is my logic here correct or incorrect?
Also, if you need me to rephrase the question, I can do that as I understand this might be hard to follow, I'm just panicking a little.
Your logic seems fine, but since code is not at all upto the mark its difficult to verify. I have written code in english commented format, if you are able to fill in the blanks all will fall in place.
Let's breakdown the problem in two sections :
Remove unwanted characters from string
Check if string returned from step1 is a pallindrome.
Create two functions :
String cleanUp(String arg){
//create a stringbuffer from arg
//start for loop
//delete unwanted chars from stringbuffer
//end loop
//make string from stringbuffer and return
}
boolean pallindrome(String arg){
//create a new string from arg reverse
//return true if reversed string and arg are same
}
Now call these functions from your main method.

How to take integer and remove other data types from the file java?

I do not know how to take the integer and ignore the strings from the file using scanner. This is what I have so far. I need to know how to read the file token by token. Yes, this is a homework problem. Thank you so much.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ClientMergeAndSort{
public static void main(String[] args){
int length = 13;
try{
Scanner input = new Scanner(System.in);
System.out.print("Enter the file name with extention : ");
File file = new File(input.nextLine());
input = new Scanner(file);
while (!input.hasNextInt()) {
input.next();
}
int[] arraylist = new int[length];
for(int i =0; i < length; i++){
length++;
arraylist[i] = input.nextInt();
System.out.print(arraylist[i] + " ");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Take a look at the API for what you're doing.
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNextInt()
Specifically, Scanner.hasNextInt().
"Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. The scanner does not advance past any input."
So, your code:
while (!input.hasNextInt()) {
input.next();
}
That's going to look and see if input hasNextInt().
So if the next token - one character - is an int, it's false, and skips that loop.
If the next token isn't an int, it goes into the loop... and iterates to the next character.
That's going to either:
- find the first number in the input, and stop.
- go to the end of the input, not find any numbers, and probably hits an IllegalStateException when you try to keep going.
Write down in words what you want to do here.
Use the API docs to figure out how the hell to tell the computer that. :) Get one bit at a time right; this has several different parts, and the first one doesn't work yet.
Example: just get it to read a file, and display each line first. That lets you do debugging; it lets you build one thing at a time, and once you know that thing works, you build one more part on it.
Read the file first. Then display it as you read it, so you know it works.
Then worry about if it has numbers or not.
A easy way to do this is read all the data from file in a way that you prefer (line by line for example) and if you need to take tokens, you can use split function (String.split see Java doc) or StringTokenizer for each line of String that you are reading using a loop, in order to create tokens with a specific delimiter (a space for example) so now you have the tokens and you can do something that you need with them, hope you can resolve, if you have question you can ask.
Have a nice programming.
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String args[]) throws IOException {
String newStr=new String(readAllBytes(get("data.txt")));
Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher(newStr);
while (m.find()) {
System.out.println("- "+m.group());
}
}
}
This code fill read the file and then using the regular expression you can get only Integer values.
Note: This code works in Java 8
I Think This will work for you requirement.
Before reading the data from the file initially,try to write some content to the file by using scanner and filewriter then try to execute the below code snippet.
File file = new File(your filepath);
List<Integer> list = new ArrayList<Integer>();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String str =null;
while(true) {
str = bufferedReader.readLine();
if(str!=null) {
System.out.println(str);
char[] chars = str.toCharArray();
String finalInt = "";
for(int i=0;i<chars.length;i++) {
if(Character.isDigit(chars[i])) {
finalInt=finalInt+chars[i];
}
}
list.add(Integer.parseInt(finalInt));
System.out.println(list.size());
System.out.println(list);
} else {
break;
}
}
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
The final println statement will display all the integer in your file line by line.
Thanks

Java format word in string

For example I have a text file that contains the contents of each line of a book, I have a java program to search for a particular word in those lines from the book.
This is the program:
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
public class AliceSearch {
public static void main(String[] args) throws Exception {
ArrayList<String> aiw = new ArrayList<String>();
ArrayList<String> matches = new ArrayList<String>();
Scanner scan = new Scanner(new File("aiw.txt"));
Scanner input = new Scanner(System.in);
while (scan.hasNext()){
aiw.add(scan.nextLine());
}
String searchTerm;
System.out.print("Please Input Search Parameter : ");
searchTerm = input.nextLine();
boolean itemFound = false;
String currItem = null;
for(int i = 0; i<aiw.size(); i++ ) {
currItem = (String)aiw.get(i);
if (currItem.contains(searchTerm)) {
matches.add(currItem);
itemFound = true;
}
}
System.out.println("");
if ( itemFound == false ) {
System.out.println ( "No results containing "+searchTerm );
}else{
System.out.println ( "We Found the following results : " );
for(int r = 0; r < matches.size(); r++){
System.out.println("");
System.out.println(matches.get(r));
}
}
scan.close();
input.close();
}
}
I would like the searchTerm from each resultant line to be in uppercase when outputed (or when placed in the matches ArrayList). How would i go about this? I know that you use .toUpperCase(); but I do not now how i can change one word in a string of words.
Thanks in advance!
Instead of outputting it the way you do it right now:
System.out.println(matches.get(r));
can't you use
System.out.println(matches.get(r).replace(searchTerm, searchTerm.toUpperCase()));
Here is the JavaDoc for the replace() method used to replace the found word with it's uppercase version. It would be better to have
String uppercase = searchTerm.toUpperCase();
outside of the loop and then use
System.out.println(matches.get(r).replace(searchTerm, uppercase));
There is a method on String that should fit your use case exactly:
line.replace(word, word.toUpperCase());
This can be easily done using replace functionality of the pattern. We surely also need to highlight the partially capitalized words (start of the sentence, for instance), so need to create a Pattern with flags, cannot just use String.replaceAll():
Pattern highlight = Pattern.compile(
Pattern.quote(word), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE );
String hw = word.toUpperCase();
line = highlight.matcher(line).replaceAll(hw);
The first two lines should be prepared in advance as soon as the word is known. There is no need to recompute them newly for every found line. Pattern.quote quotes reserved characters so they will be given no special meaning.

Space Replacement for Float/Int/Double

I am working on a class assignment this morning and I want to try and solve a problem I have noticed in all of my team mates programs so far; the fact that spaces in an int/float/double cause Java to freak out.
To solve this issue I had a very crazy idea but it does work under certain circumstances. However the problem is that is does not always work and I cannot figure out why. Here is my "main" method:
import java.util.Scanner; //needed for scanner class
public class Test2
{
public static void main(String[] args)
{
BugChecking bc = new BugChecking();
String i;
double i2 = 0;
Scanner in = new Scanner(System.in);
System.out.println("Please enter a positive integer");
while (i2 <= 0.0)
{
i = in.nextLine();
i = bc.deleteSpaces(i);
//cast back to float
i2 = Double.parseDouble(i);
if (i2 <= 0.0)
{
System.out.println("Please enter a number greater than 0.");
}
}
in.close();
System.out.println(i2);
}
}
So here is the class, note that I am working with floats but I made it so that it can be used for any type so long as it can be cast to a string:
public class BugChecking
{
BugChecking()
{
}
public String deleteSpaces(String s)
{
//convert string into a char array
char[] cArray = s.toCharArray();
//now use for loop to find and remove spaces
for (i3 = 0; i3 < cArray.length; i3++)
{
if ((Character.isWhitespace(cArray[i3])) && (i3 != cArray.length)) //If current element contains a space remove it via overwrite
{
for (i4 = i3; i4 < cArray.length-1;i4++)
{
//move array elements over by one element
storage1 = cArray[i4+1];
cArray[i4] = storage1;
}
}
}
s = new String(cArray);
return s;
}
int i3; //for iteration
int i4; //for iteration
char storage1; //for storage
}
Now, the goal is to remove spaces from the array in order to fix the problem stated at the beginning of the post and from what I can tell this code should achieve that and it does, but only when the first character of an input is the space.
For example, if I input " 2.0332" the output is "2.0332".
However if I input "2.03 445 " the output is "2.03" and the rest gets lost somewhere.
This second example is what I am trying to figure out how to fix.
EDIT:
David's suggestion below was able to fix the problem. Bypassed sending an int. Send it directly as a string then convert (I always heard this described as casting) to desired variable type. Corrected code put in place above in the Main method.
A little side note, if you plan on using this even though replace is much easier, be sure to add an && check to the if statement in deleteSpaces to make sure that the if statement only executes if you are not on the final array element of cArray. If you pass the last element value via i3 to the next for loop which sets i4 to the value of i3 it will trigger an OutOfBounds error I think since it will only check up to the last element - 1.
If you'd like to get rid of all white spaces inbetween a String use replaceAll(String regex,String replacement) or replace(char oldChar, char newChar):
String sBefore = "2.03 445 ";
String sAfter = sBefore.replaceAll("\\s+", "");//replace white space and tabs
//String sAfter = sBefore.replace(' ', '');//replace white space only
double i = 0;
try {
i = Double.parseDouble(sAfter);//parse to integer
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
System.out.println(i);//2.03445
UPDATE:
Looking at your code snippet the problem might be that you read it directly as a float/int/double (thus entering a whitespace stops the nextFloat()) rather read the input as a String using nextLine(), delete the white spaces then attempt to convert it to the appropriate format.
This seems to work fine for me:
public static void main(String[] args) {
//bugChecking bc = new bugChecking();
float i = 0.0f;
String tmp = "";
Scanner in = new Scanner(System.in);
System.out.println("Please enter a positive integer");
while (true) {
tmp = in.nextLine();//read line
tmp = tmp.replaceAll("\\s+", "");//get rid of spaces
if (tmp.isEmpty()) {//wrong input
System.err.println("Please enter a number greater than 0.");
} else {//correct input
try{//attempt to convert sring to float
i = new Float(tmp);
}catch(NumberFormatException nfe) {
System.err.println(nfe.getMessage());
}
System.out.println(i);
break;//got correct input halt loop
}
}
in.close();
}
EDIT:
as a side note please start all class names with a capital letter i.e bugChecking class should be BugChecking the same applies for test2 class it should be Test2
String objects have methods on them that allow you to do this kind of thing. The one you want in particular is String.replace. This pretty much does what you're trying to do for you.
String input = " 2.03 445 ";
input = input.replace(" ", ""); // "2.03445"
You could also use regular expressions to replace more than just spaces. For example, to get rid of everything that isn't a digit or a period:
String input = "123,232 . 03 445 ";
input = input.replaceAll("[^\\d.]", ""); // "123232.03445"
This will replace any non-digit, non-period character so that you're left with only those characters in the input. See the javadocs for Pattern to learn a bit about regular expressions, or search for one of the many tutorials available online.
Edit: One other remark, String.trim will remove all whitespace from the beginning and end of your string to turn " 2.0332" into "2.0332":
String input = " 2.0332 ";
input = input.trim(); // "2.0332"
Edit 2: With your update, I see the problem now. Scanner.nextFloat is what's breaking on the space. If you change your code to use Scanner.nextLine like so:
while (i <= 0) {
String input = in.nextLine();
input = input.replaceAll("[^\\d.]", "");
float i = Float.parseFloat(input);
if (i <= 0.0f) {
System.out.println("Please enter a number greater than 0.");
}
System.out.println(i);
}
That code will properly accept you entering things like "123,232 . 03 445". Use any of the solutions in place of my replaceAll and it will work.
Scanner.nextFloat will split your input automatically based on whitespace. Scanner can take a delimiter when you construct it (for example, new Scanner(System.in, ",./ ") will delimit on ,, ., /, and )" The default constructor, new Scanner(System.in), automatically delimits based on whitespace.
I guess you're using the first argument from you main method. If you main method looks somehow like this:
public static void main(String[] args){
System.out.println(deleteSpaces(args[0]);
}
Your problem is, that spaces separate the arguments that get handed to your main method. So running you class like this:
java MyNumberConverter 22.2 33
The first argument arg[0] is "22.2" and the second arg[1] "33"
But like other have suggested, String.replace is a better way of doing this anyway.

Categories

Resources