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

Я пытаюсь запустить задание mapreduce на hadoop, которое считывает пятую запись файла с разделителями табуляции (пятая запись — отзывы пользователей), а затем выполняет некоторый анализ настроений и подсчитывает количество слов в них.

Однако, как вы знаете из отзывов пользователей, они обычно содержат разрывы строк и пустые строки. Мой код повторяет слова каждого отзыва, чтобы найти ключевые слова и проверить настроение, если ключевое слово найдено.

Проблема в том, что когда код повторяет обзор, он выдает мне ошибку ArrayIndexOutofBoundsException из-за этих разрывов строк и пустых строк в одном обзоре.

Я пытался использовать replaceAll("\r", " ") и replaceAll("\n", " ") безрезультатно.

Я также пробовал if (tokenizer.countTokens() == 2){ word.set(tokenizer.nextToken());} else { }

тоже безрезультатно. Ниже мой код:

public class KWSentiment_Mapper extends Mapper<LongWritable, Text, Text, IntWritable> {
ArrayList<String> keywordsList = new ArrayList<String>();
ArrayList<String> posWordsList = new ArrayList<String>();
ArrayList<String> tokensList = new ArrayList<String>();
int e;

@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

    String[] line = value.toString().split("\t");
    String Review = line[4].replaceAll("[\\-\\+\\\\)\\.\\(\"\\{\\$\\^:,]", "").toLowerCase();

    StringTokenizer tokenizer = new StringTokenizer(Review);

    while (tokenizer.hasMoreTokens()) {
        // 1- first read the review line and store the tokens in an arraylist, 2-
        // iterate through review to check for KW if found
        // 3-check if there's PosWord near (upto +3 and -2)
        // 4- setWord & context.write 5- null the review line arraylist
        String CompareString = tokenizer.nextToken();

        tokensList.add(CompareString);
    }
    {
    for (int i = 0; i < tokensList.size(); i++)

    {

        for (int j = 0; j < keywordsList.size(); j++) {
            boolean flag = false;

            if (tokensList.get(i).startsWith(keywordsList.get(j)) == true) {

                for (int e = Math.max(0, i - 2); e < Math.min(tokensList.size(), i + 4); e++) {

                    if (posWordsList.contains(tokensList.get(e))) {

                        word.set(keywordsList.get(j));
                        context.write(word, one);
                        flag = true;

                        break; // breaks out of e loop }}
                    }
                }
            }
            if (flag)
                break;
        }
    }
    tokensList.clear();
}

}

Ожидаемые результаты таковы, что: Возьмем эти два случая отзывов, в которых возникает ошибка:

Кейс 1: "Красиво и просторно!
Я очень рекомендую это место и отличного хозяина.»

Случай 2: «Место в целом было очень тихим, но мы не чувствовали себя засидевшимися.

Помимо этого, ванная комната большая, а душ действительно хороший, но есть проблема. "

Система должна читать весь обзор как одну строку и перебирать слова в ней. Однако он просто останавливается, когда находит разрыв строки или пустую строку, как в случае 2.
. Случай 1 следует читать так: «Красиво и просторно! Я очень рекомендую это место и отличного хозяина».

Случай 2 должен быть таким: «Место в целом было очень тихим, но мы не чувствовали себя засидевшимися. Помимо этого, ванная большая, а душ действительно хороший, но есть проблема».

У меня мало времени, и я был бы очень признателен за помощь здесь.

Спасибо!

Неужели непонятно, вот пример текстового файла, который читает система. >1302369 134958657 8417768 Anon "Красиво и просторно! Я очень рекомендую это место и отличного хозяина." >1401724 87802333 82672125 Аноним "Поскольку наш поезд прибыл около 6:30 утра, мы дали Лие знать, можем ли мы оставить наш багаж, и она любезно согласилась. Мы прибыли к ней в 6:45 утра. Кроме того, ванная комната большая и душ действительно хороший, но есть знак, который не описан."

R.A 21.01.2019 19:56

Пожалуйста, добавьте образец ввода в сам вопрос с соответствующим форматированием.

Ben Watson 22.01.2019 15:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
416
2

Ответы 2

Итак, я надеюсь, что понимаю, что вы пытаетесь сделать.... Если я правильно понимаю то, что у вас есть выше, значение «значение», переданное в вашу функцию карты выше, содержит значение с разделителями, из которого вы хотели бы проанализировать отзывы пользователей. Если это так, я считаю, что мы можем использовать функцию экранирования в библиотеке opencsv, используя табуляцию в качестве символа-разделителя вместо запятых, чтобы правильно заполнить поле обзора пользователя: http://opencsv.sourceforge.net

В этом примере мы читаем одну строку из переданного ввода и анализируем ее в «столбцах» на основе символа табуляции и помещаем результаты в массив «nextLine». Это позволит нам использовать функцию экранирования CSVReader, не читая фактический файл, а вместо этого используя значение текста, переданного в вашу функцию карты.

        StringReader reader = new StringReader(value.toString());
        CSVReader csvReader = new CSVReader(reader, '\t', '\"', '\\', 0);

        String [] nextLine = csvReader.readNext();
        if (nextLine != null && nextLine.length >= 5) {
           // Do some stuff
        }

В примере, который вы вставили выше, я думаю, что даже этот split("\n") будет проблематичным, поскольку вкладки в пользовательском обзоре разделены на два результата в результате в дополнение к тому, что новые строки обрабатываются как новые записи. Но оба этих символа допустимы, если они находятся внутри значения в кавычках (как они должны быть в правильно экранированном файле и как в вашем примере). CSVReader должен обрабатывать все это.

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

Christopher 21.01.2019 20:04

Привет @Christopher Спасибо за ваш ответ. Мне жаль. Кажется, я неправильно понял ваш вопрос. Входной файл, который я пытаюсь прочитать, сохранен в HDFS. Эта программа предназначена для запуска задания Hadoop mapreduce. Итак, почему читатель CSV не будет работать в этом случае

R.A 21.01.2019 20:04

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

Christopher 21.01.2019 20:07

Я изменил название вопроса, так как оно кажется вводящим в заблуждение. Извинения за это. Как упоминалось в моем комментарии выше, входной файл, который читает система, сохраняется и считывается из HDFS построчно. То есть каждая строка файла с разделителями табуляцией сначала читается целиком. В моем коде выше эти две строки важны String[] line = value.toString().split("\t"); Просмотр строки = строка[4].toLowerCase(); @Christopher Спасибо за модификацию и за то, что обратили мое внимание на двусмысленность вопроса. Я изменил вопрос сейчас.

R.A 21.01.2019 20:21

@RA Я снова обновился. Надеюсь, я понимаю, что вы сейчас делаете?

Christopher 21.01.2019 20:45

Большое спасибо еще раз. «Текст» в функции KWSentiment_Mapper передается функции карты, в которой анализируется отзыв пользователя. Я действительно попробую вышеперечисленное. Только один вопрос: нужно ли сохранять входной файл в формате CSV, чтобы можно было использовать CSVReader?

R.A 21.01.2019 21:03

@RA, вам не нужно ничего сохранять в этом примере. Анализ строки выполняется с помощью объекта StringReader, который инициализируется из переданного текстового значения и существует в памяти. Я добавил еще пару предложений к объяснению.

Christopher 21.01.2019 21:15

Проверяйте каждую строку в начале метода map, чтобы знать, что line[4] существует и не является нулевым.

if (value == null || value.toString == null) {
    return;
}

String[] line = value.toString().split("\t");
if (line == null || line.length() < 5 || line[4] == null) {
    return;
}

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

Другие вопросы по теме