Вытягивание нескольких частей строки - PullRequest
2 голосов
/ 14 октября 2019

Файл, в котором я читаю, выглядит следующим образом

textBox25,textBox21,textBox20,textBox1,textBox9,textBox10,textBox6,textBox5,textBox4,textBox3,textBox12,textBox11
"Smith, Lehron",2019,40,Billable,4.10,"Smith, Lehron",2019,40,% Billable,61.50 %,% Billable & Appt.,61.50 %
"Smith, Lehron",2019,40,Non Bill.,2.57,,,,,,,

Я пытаюсь добавить несколько частей разбиения в массив. В настоящее время он выплевывает его имя из позиции 1, но мне также нужно, чтобы оно читалось в Billable 4.10 и Non Bill 2.57, так что оно выплевывает что-то вроде

Smith, Lehron, Billable 4.10, Non Bill 2.57

Любые идеи или помощь будут оценены!

public static void main(String[] args)throws IndexOutOfBoundsException, IOException {

    Scanner in;
    in = new Scanner (System.in);

    File cisStaffHours = new File("StaffHoursOverviewReport_10102019 (1).txt");
    Scanner s = new Scanner(cisStaffHours);

    PrintWriter outFile;
    outFile = new PrintWriter(new FileWriter("outFile.txt"));

    ArrayList<Tracking> listInfo = new ArrayList<Tracking>();

    while (s.hasNextLine()){

        Tracking c = new Tracking();
        c.name = s.nextLine();

        if(c.name.contains("\"")) {
            c.name=s.nextLine();
            c.name=s.nextLine();
            String[] parts = c.name.split("\"");
            c.name=parts[1];
            listInfo.add(c);
        }
    }

    for(Tracking o: listInfo) {
        outFile.println(o.name);
    }
        outFile.close();
        System.out.println(listInfo);
    }
}

1 Ответ

1 голос
/ 15 октября 2019

Похоже, у вас есть текстовый файл в формате CSV, в котором есть определенные строки столбчатых данных, разделенных запятыми. Однако обычно CSV-файл начинается со строки Header , указывающей имена столбцов (хотя и не всегда), в которых вы, как представляется, не нуждаетесь, поэтому мы можем игнорировать эту часть.

Я думаю, что идеальной ситуацией в данном конкретном случае был бы метод, который считывает текстовый файл и может извлекать все или определенные столбцы данных из каждой строки, когда этот файл читается. Полученные данные затем записываются в предоставленный выходной файл.

Небольшая проблема заключается в том, что некоторые столбцовые данные находятся в кавычках ("..."), некоторые из которых также содержат тот же самый разделитель, который разделяет все остальные столбцы в любой данной строке записи. Это может создать проблему, поэтому необходимо соблюдать осторожность, чтобы справиться с этой ситуацией при извлечении данных, в противном случае неполные данные могут быть получены и записаны в нужный выходной файл и возвращены в 2D String Array.

Пример кода, который я предоставляю нижеделает все это в рамках одного метода. Он является относительно базовым, поэтому вам придется иметь дело с какими-либо конкретными улучшениями, если это потребуется. Метод содержит три параметра, два типа String и один из необязательных int args [], и возвращает двумерный массив строк, содержащий полученные данные. Если вы не хотите, чтобы метод возвращал что-либо, код может быть несколько уменьшен.

Вот метод getFromCSV () . Это хорошо прокомментировано:

/**
 * This is a very basic parsing type method.<br><br>
 * 
 * Usage: {@code String[][] data = getFromCSV("Data.txt", "DataOutput.txt", 13, 16, 17, 28, 29); }
 * 
 * @param csvFilePath (String) The full path and file name of the Data file.<br>
 * 
 * @param destinationPath (String) The full path and file name of the desired output file. 
 * the retrieved data will be store there.<br>
 * 
 * @param desiredLiteralColumns (Optional - Integer Args or int[] Array) The literal
 * data columns to acquire row data from. The arguments can be provided in any desired
 * order. The returned Array will hold the required data in the order your provided.<br>
 * 
 * @return (2D String Array) Containing columnar data from each data row.
 */
public static String[][] getFromCSV(String csvFilePath, String destinationPath, 
                                    int... desiredLiteralColumns) {
    String ls = System.lineSeparator();   // The Line-Separator used for current OS.
    /* Does the destination Path exist? 
       If not create it before file is created. */
    File destPath = new File(destinationPath);
    if (!destinationPath.trim().equals("") && destPath.getParentFile() == null) {
        String fPath = destPath.getAbsolutePath().substring(0, destPath.getAbsolutePath().lastIndexOf("\\"));
        new File(fPath).mkdirs();
    }
    else {
        destPath.getParentFile().mkdirs();
    }

    ArrayList<String[]> list = new ArrayList<>();
    ArrayList<String> lineData = new ArrayList<>();
    File cisStaffHours = new File(csvFilePath);
    // 'Try With Resources' is used here to auto-close the reader.
    try (Scanner reader = new Scanner(cisStaffHours)) {
        String fileLine = "";
        // 'Try With Resources' is used here to auto-close the writer.
        try (PrintWriter writer = new PrintWriter(new FileWriter(destPath))) {
            while (reader.hasNextLine()) {
                /* Read lines one at a time. Trim each read in 
                  line of leading or trailing white-spaces (if any).  */
                fileLine = reader.nextLine().trim(); 
                // Skip blank lines (if any).
                if (fileLine.equals("")) {
                    continue;
                }
                /* Split the line based on a comma (,) delimiter)...
                   (DO NOT split on commas within quotation marks!).
                   The regular expression used with the split() method
                   ignores any number of white-spaces before or after
                   the delimiter.                    */
                String[] lineParts = fileLine.split("\\s{0,},\\s{0,}(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);

                //Do we only want specific columns only?
                if (desiredLiteralColumns.length > 0) {
                    // Yes...
                    lineData.clear(); // Clear the ArrayList in case it already contains something.
                    // Retrieve the desired columns an place them into a String ArrayList...
                    for (int dc : desiredLiteralColumns) {
                        for (int lp = 0; lp < lineParts.length; lp++) {
                            if (dc == (lp + 1)) {
                                lineData.add(lineParts[lp]);
                                break;
                            }
                        }
                    }
                    /* Convert the 'lineData' ArrayList to a 1D String Array
                       and then add that String Array to the 'list' ArrayList. */
                    list.add(lineData.toArray(new String[0]));

                    // Build and Write the acquired data to the desired output file.
                    String dataString = lineData.get(0).replace("\"", "") + ", " + 
                    lineData.get(1) + " " + lineData.get(2) + " , " + 
                    lineData.get(3).replace(".", " ") + lineData.get(4);
                    writer.println(dataString);
                    writer.flush();
                }
                else {
                    // No, we want all columns. Add all columnar data to the ArrayList...
                    list.add(lineParts);
                    // Build and Write the acquired data to the desired output file.
                    String dataString = lineData.get(0).replace("\"", "") + ", " + 
                    lineData.get(1) + " " + lineData.get(2) + " , " + 
                    lineData.get(3).replace(".", " ") + lineData.get(4);
                    writer.println(dataString);
                    writer.flush();
                }
            }
        }
        // Catch and display any exceptions,
        catch (IOException ex) {
            System.out.println("getFromCSV() Method Error!" + ls + ex.getMessage());
        }
    }
    catch (FileNotFoundException ex) {
        System.out.println("getFromCSV() Method Error!" + ls + ex.getMessage());
    }

    /* Convert list to a 2D String Array and then 
       return the 2D Array...         */
    String[][] array = new String[list.size()][];
    for (int i = 0; i < list.size(); i++) {
        array[i] = list.get(i);
    }
    return array;
}

Как видите, метод требует три параметра:

Параметр csvFilePath:

Здесь должен быть указан строковый аргумент, который указывает, где находится текстовый файл для чтения в локальной файловой системе. Если текстовый файл находится внутри Class-Path, тогда достаточно только имени файла. Если нет, то ожидается полный путь и имя файла.

Параметр destinationPath:

Здесь необходимо указать строковый аргумент, который указывает, гдевыходной текстовый файл должен быть создан и записан в локальной файловой системе. Если выходной файл должен находиться в папке проекта приложения, то достаточно только имени файла. Если нет, то ожидается полный путь и имя файла к нему. Убедитесь, что в вашей операционной системе есть разрешения для достижения этой цели. Если указанный путь назначения еще не существует в локальной файловой системе, он автоматически создается, опять же, убедитесь, что в вашей операционной системе есть разрешения для достижения этого.

Параметр requiredLiteralColumns:

Здесь можно указать либо целочисленный массив ( int [] ), либо серию целочисленных аргументов, разделенных запятыми, которые обозначают нужные литеральные столбцы для извлеченияданные из каждой строки данных файла. Под " literal " мы подразумеваем, что данные, расположенные в индексе столбца 0, являются буквально столбцом 1. Данные в индексе столбца 7 - это буквально столбец 8. Это буквальные значения, которые вы хотите указать. Вот краткий пример:

Если в файле есть строка данных, которая выглядит следующим образом:

"Doe, John", 62, "6558 Cook Road, Atlanta, Georgia", 30336, $78,564.77

, и мы хотим получить данные в 1-м столбце (имя пользователя), 3-мстолбец (адрес) и 4-й столбец (почтовый индекс), то мы могли бы предоставить следующее для getFromCSV () метод:

String[][] myData = getFromCSV("My_CSV_File.csv", "MY_Output_File.txt", 1, 3, 5);

                                O R

int[] columns = {1, 3, 5};
String[][] myData = getFromCSV("C:\\MyDataFile\\My_CSV_File.csv",
                               "C:\\MyOuputFiles\\MY_Output_File.txt", 
                               columns);

Затем, когда код запускается, выходной файли возвращенный 2D String Array будет содержать:

"Doe, John", "6558 Cook Road, Atlanta, Georgia", 30336

Если для необязательного параметра requiredLiteralColumns не заданы аргументы, то все Получаются данные столбца, поэтому:

String[][] myData = getFromCSV("My_CSV_File.csv", "MY_Output_File.txt");

поместит следующее в выходной файл, и возвращенный 2D String Array будет содержать то же самое.

"Doe, John", 62, "6558 Cook Road, Atlanta, Georgia", 30336, $78,564.77

Я полагаю, что существуют проблемы с позиционированием разделителя в строках данных, которые вы указали в своем сообщении в качестве примера. Я думаю, что вы пропустили несколько запятых. Посмотрите на это внимательно . Как только вы это сделаете .... Чтобы построить именно то, что вам нужно, вы должны сделать что-то вроде этого:

String[][] data = getFromCSV("StaffHoursOverviewReport_10102019 (1).txt",
                             "outFile.txt", 
                             13, 16, 17, 28, 29);
for (int i = 0; i < data.length; i++) {
    String dataString = data[i][0].replace("\"", "") + ", " + 
                        data[i][1] + " " + data[i][2] + " , " + 
                        data[i][3].replace(".", " ") + data[i][4];
    System.out.println(dataString);
}

Этот должен выводить на консольокно и поместите его в желаемый выходной файл:

Smith, Lehron, Billable 4.10 , Non Bill 2.57

, что составляет точно , как в примере, который вы предоставили для желаемого вывода. Испытано!

...