Java使用正则表达式提取字段分隔的子字符串
Posted
技术标签:
【中文标题】Java使用正则表达式提取字段分隔的子字符串【英文标题】:Java extract field delimited substring using regex 【发布时间】:2013-10-14 22:17:03 【问题描述】:如何使用正则表达式从系统日志消息中提取程序名?我有一个 Java 流处理模块,它接受正则表达式来处理 syslog 消息。
日志行可能是:
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_.-]+))
,它似乎可以工作,但老实说,我修改了一个示例正则表达式并使用在线工具对其进行调整,直到它适合我的用例,但我不确定它是如何工作的。
【问题讨论】:
是的。这是可能的。你试过什么? 我尝试的是“((?:[A-Za-z][A-Za-z0-9_.-]+))”,它似乎有效,但老实说,我修改了一个示例正则表达式并使用在线工具对其进行调整,直到它适合我的用例,但我不确定它是如何工作的。 【参考方案1】:双split
应该可以胜任:
String token = data.split(" +")[2].split("[\\[:/]")[0];
【讨论】:
我正在将水槽配置中的正则表达式传递给正则表达式拦截器,因此我无法使用 Java 库/函数。 您将问题标记为 Java 并且不能使用 Java 最常见的 String 类方法? 我将它标记为 Java,因为我认为正则表达式需要与 Java 兼容。我不认为 unix shell 或 Perl 正则表达式语法适用于 Java 1:1。【参考方案2】:试试这样的:
String str = line.split(" ")[2].replaceAll("(.+)(\\[|\\:|\\/).+", "$1");
没有测试过。
【讨论】:
我正在将水槽配置中的正则表达式传递给正则表达式拦截器,因此我无法使用 Java 库/函数。【参考方案3】:我认为您正在寻找的正则表达式是:
String regex = "([^\\[:/]+).*";
.*
表示匹配 0 个或多个任意字符。在点星 ().*
前面放置一对括号会创建一个可以从 Matcher 中选择的组。由于它是第一组括号,因此它由组号 1 引用。括号内是一个表达式,它匹配一个或多个否定字符类[^]+
,其中包含 OP 中指定的字符,特别是“[”, “:”和“/”字符。
这是一个测试结果的示例应用程序:
package com.stackexchange.***;
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"
【讨论】:
我将正则表达式作为配置传递给另一个模块,因此无法使用拆分。 这是否意味着每个输入行实际上来自 InputStream 而不是 List如果您的示例数据与您提供的完全一样:
(?:.+?\s)2([\w\.]+).+$
解释:
(?:.+?\s)2
...匹配第二个空格
([^\s[:/]+)
...匹配任何不是''、':'或'/'的东西
.+$
...匹配 EOL
你想要的将在捕获组\1
【讨论】:
对我不起作用。如果我把你的正则表达式和一个示例日志行在这里尝试一下:java-regex-tester.appspot.com - 你的正则表达式匹配整行。以上是关于Java使用正则表达式提取字段分隔的子字符串的主要内容,如果未能解决你的问题,请参考以下文章