3

I am currently stuck with a problem. I am supposed to write a programm that is able to search for a string in a .txt file given as argument. The programm must return the row and the column of the found string. I am struggling to find a way to achieve that and have no idea how to go on. I would be very happy to hear from you.

Here is my attempt in tackling with my task: - I thought about saving the content of a file via a buffered reader in a string array, but that does not seem to work since I cannot define the length of the array from the beginning - I also thought about saving the content of the file via a buffered reader in a string and then split this string in characters. However I am not sure how I will be able to retreieve the rows in the original file then.

This is the non-functional code that I have at the moment:

public class StringSearch{
    public static void main(String[] args){
        if(args.length > 0){
            BufferedReader br = null;
            String text = null;
            try{
                br = new BufferedReader(new FileReader(args[0]));
                // attempt of saving the content of the "argument" file in a string array and then in a        string
                String[] lines = new String[]; // I know this does not work like this 
                for( int i = 0; i < lines.length; i++){
                    lines[i] = br.readLine;
                    text = text + lines[i];
                    i++;
                }
                text.split("\r\n");

            } catch (IOException ioe){
                ioe.printStackTrace();
            } finally{
                if (br != null) {
                    try{
                        br.close();
                    }catch (IOException ioe){
                        ioe.printStackTrace();
                    }
                }


            }

        }
    }
}

2 Answers2

1

Here's one approach -

  1. Let's consider a counter which holds a counter for all the readLine() method invocations - representing the "row" in the .txt file. So, increment the counter after every readLine call in the while loop.
  2. Next, split the line on " " (space) to get an array of each word in the line. Then, you could iterate over this array and match the word to the search string. The position of array index at the time the match was found will represent the "column".
S B
  • 384
  • 2
  • 8
  • thank you so much for your answer. I am still unclear about what I should do first with the text. Should I read lines and save them into a string or into a string array? What is advisable? – rhododendron Feb 01 '20 at 13:17
  • 1
    You could dynamically parse through the text. And only store the "row" and "column" values when you find a match. You could use a relevant data structure to store these in case of multiple matches. – S B Feb 01 '20 at 13:22
1

You can do it as follows:

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("The correct syntax to use this program is: java Main <filename.txt> <text-to-search>");
            return;
        }
        Scanner scanner;
        File file = new File(args[0]);
        int rowCount = 1, index;
        String line;

        // Map to collect row and col info of the search string
        Map<String, String> lineColMap = new HashMap<String, String>();

        if (!file.exists()) {
            System.out.println("The file, " + args[0] + " does not exist");
            return;
        }
        try {
            scanner = new Scanner(file);
            while (scanner.hasNextLine()) {// Loop until the last line in the file
                line = scanner.nextLine();// Read a line from the file
                index = line.indexOf(args[1]);// Find if the string exists in the line
                if (index != -1) {// If the string exists
                    // Put the row and col info of the search string into the map
                    lineColMap.put("Row: " + rowCount, "Column: " + index);
                }
                rowCount++;// Increase the row count
            }
        } catch (Exception e) {
            System.out.println("Error occured while processing the file");
            e.printStackTrace();
        }
        if (lineColMap.entrySet().size() > 0) {// If there is at least one entry collected into the map
            System.out.println("'" + args[1] + "' exists in " + args[0] + " as follows:");
            for (Map.Entry<String, String> entry : lineColMap.entrySet()) {
                System.out.println(entry.getKey() + ", " + entry.getValue());
            }
        } else {
            System.out.println("'" + args[1] + "' does not exist in " + args[0]);
        }
    }
}

A sample run: java Main input.txt of

'of' exists in input.txt as follows:
Row: 1, Column: 51
Row: 2, Column: 50
Row: 3, Column: 50
Row: 5, Column: 71

The content of input.txt is as follows:

Stack Overflow is a question and answer site for professional and enthusiast programmers.
It is a privately held website, the flagship site of the Stack Exchange Network, created in 2008 by Jeff Atwood and Joel Spolsky.
It features questions and answers on a wide range of topics in computer programming.
It was created to be a more open alternative to earlier question and answer sites such as Experts-Exchange.
The name for the website was chosen by voting in April 2008 by readers of Coding Horror, Atwood's popular programming blog.

The logic in the code is straight forward and I believe, you should be able to understand it in the first reading. Feel free to comment in case of any doubt.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • thank you so much for your input and thorough help! It is ingenious to choose a HashMap to store the row and column number but I do not understand how it works. The HashMap is declared for Strings and yet the rowCount and index are integers, right? Could you explain that please? Thanks a lot in advance! – rhododendron Feb 01 '20 at 14:18
  • I have stored strings only into the map e.g. the first entry is `Row: 1=Column: 51` where `Row: 1` is the key and `Column: 51` is the value; both of them are strings. If you like to store just the numbers (row number and column number), yoou can declare the map as `Map lineColMap = new HashMap();` and then you can use `lineColMap.put(rowCount, index);` to store the values into the map. Feel free to comment in case of any further doubt. – Arvind Kumar Avinash Feb 01 '20 at 14:25
  • that makes sense. Thanks again! Just one last question regarding int rowCount. You initialised it like this int rowCount = 1, index; Does this mean that it bears two values? – rhododendron Feb 01 '20 at 14:30
  • 1
    You are most welcome. `int rowCount = 1, index;` is a shortcut to declare two or more variables in a single statement. You can also write it as `int rowCount = 1; int index;` as two separate statements. In any of these two ways, `rowCount` will be initialized with `1` and `index` will be initialized with `0` (which is the default value of an `int` variable). Feel free to comment in case of any further doubt. – Arvind Kumar Avinash Feb 01 '20 at 14:33