TransWikia.com

Как использовать разделитель

Stack Overflow на русском Asked on December 25, 2021

Задача: достать из файла корректные данные. Корректные – это фамилия, зарплата и номер департамента. Все данные разделены либо слешем и произвольным количеством пробелов, либо произвольным количеством пробелов.
Также необходимо обработать ошибки, мы не должны доставать строки, в которых после знака "." в зарплате идёт более трёх чисел. Пустые строки, строки без фамилии, департамента – не нужны.

Файл с данными:

    Ситов /13000.1234134/Первый - невалидно, больше 3 цифр после точки в зп - 1234134, максимум 123 должно быть
    Курбян -13000.123/Второй - невалидный, есть минус в числе
    Кошкин 13000.123/Четвёртый- валидный, потому что фио, цифры, департамент - подходят по условию
    43242/13424/Третий - невалидный, вместо фио цифры
    Жестков/13424/43242- невалидный, вместо департамента цифры
    Петровна/привет/Третий - невалидный, вместо зп цифры
    Иванович/-10000/Третий -невалидно, есть минус у зп
     / 132/ Четвертый - невалидно, ничего нет на месте фио и зп из 3 цифр быть не может, минимум от 5 цифр
    Петров/10000/Пятый - валидно
    Иванов/30000/ШЕСТОЙ -валидно
    Сидоров/20000/Седьмой - валидно
    Пушкин/40000/Восьмой - валидно

Как я пытался сделать:

public static void main(String[] args) throws IOException {
    String s;
    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/VGilenko/Desktop/file.txt"), "CP1251"));

        while ((s = br.readLine()) != null) {
            if (s.trim().length() != 0) {
                String[] words = s.split("/");
                for (String element : words) {
                    System.out.println(element);
                }
            }
        }

        br.close();
    }
    catch (FileNotFoundException e) {
        System.out.println("Файл не был найден, нужно скорректировать путь");
    }
}

Вывод моего приложения:

Ситов 
13000.1234134
Первый
Курбян -13000.123
Второй
Иванович
-10000
Третий
 
 132
 Четвертый
Петров
10000
Пятый
Иванов
30000
ШЕСТОЙ
Сидоров
20000
Седьмой
Пушкин
40000
Восьмой

Проблема:
Понимаю, что программа проверяет на пустоту строк, но мне этого недостаточно, как мне ещё добавить условия, которые необходимы? Допустим, чтобы была проверка на пустые ячейки, например, когда фамилии нет и необходимо эту строку убрать. Нужно ли добавлять s.trim().length() == 0) в if, потому что если убрать, то он пишет "not a statement" и предлагает Exctract side effect.

3 Answers

Пожалуй, единственным адекватным решением данного вопроса являются регулярные выражения. Без них проверка сроки станет гораздо более неудобной. Вот оптимальное решение.

String regex = "[А-Яа-яЁёA-Za-z]+";
while ((s = br.readLine()) != null) {
    if (!(s = s.trim()).isEmpty()) {
        String[] strings = s.split("\s*/\s*|\s+");
        if (strings.length < 3)
            continue;
        if (!(strings[0].matches(regex) && strings[2].matches(regex)))
            continue;
        if (!strings[1].matches("\d{5}(\.\d{1,3})?"))
            continue;
        System.out.println(strings[0] + " " + strings[1] + " " + strings[2]);
    }
}

Если вы хотите, чтобы разделителем был только символ / и ничего более, четвёртую строчку надо будет написать так:
String[] strings = s.split("/");

Если вы хотите, чтобы выводилась причина, вы можете сделать так:

if (strings.length < 3) {
    System.out.println("Строка `" + s + "` имеет неверное количество слов");
    continue;
}

Answered by Имя Фамилия on December 25, 2021

Как-то так?

 while ((s = br.readLine()) != null) {
        if (!s.trim().isEmpty()) {
            String[] words = s.split("/");
            for (String element : words) {
                if(!element.trim().isEmpty())
                   System.out.println(element);
            }
        }
    }

Answered by Barmaley on December 25, 2021

Можете создать отдельную функцию, которая будет проверять каждую строку на соответствие. Например так:

public static boolean isLineOkay(String line){
    String[] parts = line.split("/");
    if(parts.length != 3){
        return false;
    }
    for(int i = 0; i < parts.length; i++){
        if (parts[i].trim().isEmpty()){
            return false;
        }
        if (i == 1 && !parts[i].trim().matches("\d+\.?\d{0,3}")){
            return false;
        }
    }
    return true;
}

и проверять каждую строчку. В случае true дальше ее обрабатывать в соов-е с Вашим заданием.

Например

while ((s = br.readLine()) != null) {
    if(isLineOkay(s)){
        // .. обрабатываем как-то
        // .. например отправляем ее в обработчик
    }
    // .. здесь ничего нет, поэтому
    // .. если строчка не пройдет проверку
    // .. ничего не произойдет. Мы просто
    // .. переходим к следующей
}

Более сложный вариант предполагает использование регулярок для парсинга. Вот пример:

package click.webelement.so;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        String inputs[] = {
                "Ситов /13000.1234134/Первый",
                "Курбян -13000.123/Второй",
                "Кошкин 13000.123/Четвёртый",
                "43242/13424/Третий",
                "Жестков/13424/43242",
                "Петровна/привет/Третий",
                "Иванович/-10000/Третий",
                "/ 132/ Четвертый",
                "Петров/10000/Пятый",
                "Иванов/30000/ШЕСТОЙ",
                "Сидоров/20000/Седьмой",
                "Пушкин/40000/Восьмой",
                " Пушкин / 40000   Восьмой"
        };
        for (String input: inputs){
            String parts[] = isLineOkay(input);
            if(parts != null){
                System.out.println("Parsed data: " + Arrays.asList(parts));
            }
        }
    }

    public static String[] isLineOkay(String line){
        final String PATTERN = "^\s*?([А-Яа-яЁё]+)\s*?(?:\/\s*?)?(\d+\.?\d{0,3})\s*?(?:\/\s*?)?([А-Яа-яЁё]+)$";
        Pattern pattern = Pattern.compile(PATTERN);
        String[] parts = new String[3];
        Matcher matcher = pattern.matcher(line);
        if(matcher.matches()){
            parts[0] = matcher.group(1);
            parts[1] = matcher.group(2);
            parts[2] = matcher.group(3);
            return parts;
        }else{
            return null;
        }
    }

}

Вывод:

Parsed data: [Кошкин, 13000.123, Четвёртый]
Parsed data: [Петров, 10000, Пятый]
Parsed data: [Иванов, 30000, ШЕСТОЙ]
Parsed data: [Сидоров, 20000, Седьмой]
Parsed data: [Пушкин, 40000, Восьмой]
Parsed data: [Пушкин, 40000, Восьмой]

P.S. - Регулярка разбирает строчку на куски позволяя частям быть окруженными любым количеством пробелов и разделяться либо слешами либо пробелами либо вообще ничем. Т.е. текстчислотекст тоже сгодиться.

Answered by Alexey R. on December 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP