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

Как извлечь имя программы из сообщения системного журнала с помощью регулярного выражения? У меня есть модуль обработки потока Java, который принимает регулярные выражения для обработки сообщений системного журнала.

Строка журнала может быть:

2013-10-14T22:05:29+00:00 hostname sshd[6359]: Connection closed by 192.168.1.10
2013-10-14T22:05:29+00:00 hostname sshd:3322 Connection closed by 192.168.1.10
2013-10-14T22:05:29+00:00 hostname sshd/6359 Connection closed by 192.168.1.10
2013-10-14T22:05:29+00:00 hostname sshd Connection closed by 192.168.1.10
2013-10-14T22:05:29+00:00 hostname SSHD[1133] Connection closed by 192.168.1.10
2013-10-14T22:05:29+00:00 hostname SSH.D[6359]: Connection closed by 192.168.1.10

Процесс извлечения строки должен быть следующим: возьмите третью подстроку, разделенную пробелом, и извлеките подстроку, оканчивающуюся на [, :, / или пробел.

Таким образом, в первых четырех примерах журнала извлеченная строка будет sshd, пятая SSHD и шестая SSH.D. Возможно ли это с помощью регулярного выражения?

Редактировать:

То, что я пробовал, это ((?:[A-Za-z][A-Za-z0-9_.-]+)), и, похоже, оно работает, но, честно говоря, я изменил пример регулярного выражения и использовал онлайн-инструмент, чтобы настроить его, чтобы он соответствовал моему варианту использования, но я не уверен, как именно это работает.


person Joe Nate    schedule 14.10.2013    source источник
comment
Ага. Это возможно. Что вы пробовали?   -  person Mena    schedule 15.10.2013
comment
Я пробовал ((?:[A-Za-z][A-Za-z0-9_.-]+)) и, похоже, работает, но, честно говоря, я изменил пример регулярного выражения и использовал онлайн-инструмент для настройте его, пока он не будет соответствовать моему варианту использования, но я не уверен, как именно он работает.   -  person Joe Nate    schedule 16.10.2013


Ответы (4)


Двойной split должен выполнить эту работу:

String token = data.split(" +")[2].split("[\\[:/]")[0];
person anubhava    schedule 14.10.2013
comment
Я передаю регулярное выражение в конфигурации флюма перехватчику регулярных выражений, поэтому я не могу использовать библиотеки/функции Java. - person Joe Nate; 16.10.2013
comment
Вы отметили вопрос как Java и не можете использовать наиболее распространенные методы класса String в Java? - person anubhava; 16.10.2013
comment
Я пометил его как Java, потому что считаю, что регулярное выражение должно быть совместимо с Java. Я не думаю, что оболочка Unix или синтаксис регулярных выражений Perl применимы 1: 1 к Java. - person Joe Nate; 16.10.2013

Попробуйте что-то вроде этого:

String str = line.split(" ")[2].replaceAll("(.+)(\\[|\\:|\\/).+", "$1");

Не проверял.

person Martijn Courteaux    schedule 14.10.2013
comment
Я передаю регулярное выражение в конфигурации флюма перехватчику регулярных выражений, поэтому я не могу использовать библиотеки/функции Java. - person Joe Nate; 16.10.2013

Я думаю, что регулярное выражение, которое вы ищете, это:

String regex = "([^\\[:/]+).*";

.* говорит, что соответствует 0 или более любых символов. Помещение пары круглых скобок перед звездочкой с точками ().* создает группу, которую можно выбрать из Matcher. Поскольку это первый набор скобок, на него ссылается номер группы 1. Внутри скобок находится выражение, которое соответствует 1 или более из класса отрицательных символов [^]+, содержащих символы, указанные в OP, в частности "[", ": ", и "/" символов.

Вот пример приложения, тестирующего результаты:

package com.stackexchange.stackoverflow;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Question19370191 {
    public static void main(String[] args) {
        String regex = "([^\\[:/]+).*";
        Pattern pattern = Pattern.compile(regex);

        List<String> lines = new ArrayList<>();
        lines.add("2013-10-14T22:05:29+00:00 hostname sshd[6359]: Connection closed by 192.168.1.10");
        lines.add("2013-10-14T22:05:29+00:00 hostname sshd:3322 Connection closed by 192.168.1.10");
        lines.add("2013-10-14T22:05:29+00:00 hostname sshd/6359 Connection closed by 192.168.1.10");
        lines.add("2013-10-14T22:05:29+00:00 hostname sshd Connection closed by 192.168.1.10");
        lines.add("2013-10-14T22:05:29+00:00 hostname SSHD[1133] Connection closed by 192.168.1.10");
        lines.add("2013-10-14T22:05:29+00:00 hostname SSH.D[6359]: Connection closed by 192.168.1.10");

        for(String line : lines) {
            String field = line.split("\\s")[2];
            String extraction = "";
            Matcher matcher = pattern.matcher(field);
            if(matcher.matches()) {
                extraction = matcher.group(1);
            }

            System.out.println(String.format("Field \"%-12s\" Extraction \"%s\"", field, extraction));
        }
    }
}

Он выводит следующее:

Field "sshd[6359]: " Extraction "sshd"
Field "sshd:3322   " Extraction "sshd"
Field "sshd/6359   " Extraction "sshd"
Field "sshd        " Extraction "sshd"
Field "SSHD[1133]  " Extraction "SSHD"
Field "SSH.D[6359]:" Extraction "SSH.D"
person axiopisty    schedule 14.10.2013
comment
Я передаю регулярное выражение другому модулю в качестве конфигурации, поэтому не могу использовать разделение. - person Joe Nate; 16.10.2013
comment
Означает ли это, что каждая строка ввода на самом деле поступает из InputStream, а не из List‹String›? - person axiopisty; 16.10.2013
comment
Я так полагаю. Регулярное выражение передается агенту Flume в качестве конфигурации для использования с перехватчиком регулярных выражений Flume. - person Joe Nate; 16.10.2013

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

(?:.+?\s){2}([\w\.]+).+$

объяснил:

(?:.+?\s){2}...соответствует второму пробелу

([^\s[:/]+)...соответствует всему, что не является ' ', ':' или '/'

.+$...соответствует EOL

то, что вы хотите, будет в захваченной группе \1

person gwillie    schedule 15.10.2013
comment
Не работает для меня. Если я возьму ваше регулярное выражение и образец строки журнала и попробую здесь: java-regex-tester.appspot .com — ваше регулярное выражение соответствует всей строке. - person Joe Nate; 16.10.2013