Pattern类
Java中的Pattern类是用于编译正则表达式的一个工具。
Pattern类位于java.util.regex
包中,它提供了一种方式来创建一个表示正则表达式的对象。这个类没有公共的构造方法,因此要创建一个Pattern对象,需要使用它的静态方法compile
,这个方法接受一个字符串参数,即你想要编译的正则表达式。一旦你有了Pattern对象,就可以使用它来创建Matcher对象,后者可以对字符串进行匹配操作。
以下是关于Pattern类的一些关键点:
- 编译正则表达式:通过调用
Pattern.compile(String regex)
方法,可以将字符串形式的正则表达式编译成Pattern对象。 - 匹配操作:虽然Pattern类可以进行简单的匹配操作,但它本身并不执行匹配。为了进行更复杂的匹配操作,如分组或多次匹配,需要与Matcher类一起使用。
- Matcher对象:通过Pattern对象的
matcher(String input)
方法,可以创建一个Matcher对象,该对象用于对指定的输入字符串进行正则表达式匹配。 - 预定义字符类:Pattern类支持预定义字符类的使用,如
\d
代表数字字符。 - 组合使用:通常,Pattern类和Matcher类会一起使用,以实现强大的正则表达式匹配功能。例如,你可以使用Pattern对象来编译正则表达式,然后使用Matcher对象来执行实际的匹配操作,并处理匹配结果。
本地数据爬取
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class LocalDataCrawler {
public static void main(String[] args) {
String filePath = "data.txt"; // 本地文件路径
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
// 处理每一行数据
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这个示例中,使用BufferedReader
和FileReader
类来读取本地文件data.txt
中的数据。在循环中,我们可以对每一行数据进行处理,例如打印出来或者进行其他操作。最后,我们使用try-with-resources语句来自动关闭文件流。
网络爬虫
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class SimpleWebCrawler {
public static void main(String[] args) {
try {
// 目标网址
String url = "https://www.example.com";
// 创建URL对象
URL obj = new URL(url);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
// 设置请求方法
connection.setRequestMethod("GET");
// 获取响应码
int responseCode = connection.getResponseCode();
System.out.println("响应码: " + responseCode);
// 读取网页内容
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// 输出网页内容
System.out.println(response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
零宽断言
Java爬虫中的零宽断言是正则表达式中的一种特殊语法,用于在匹配时进行条件判断,但不消耗字符。常见的零宽断言有以下几种:
(?=)
:正向肯定查找,表示只有当后面的内容匹配括号内的表达式时才会匹配成功。例如,a(?=b)c
表示匹配"abc",但不包括"ac"。(?!)
:否定前向肯定查找,表示只有当后面的内容不匹配括号内的表达式时才会匹配成功。例如,a(?!b)c
表示匹配"ac",但不包括"abc"。(?<=)
:正向后行肯定查找,表示只有当前面的内容匹配括号内的表达式时才会匹配成功。例如,(?<=a)b
表示匹配"ab",但不包括"ba"。(?<!)
:否定后行肯定查找,表示只有当前面的内容不匹配括号内的表达式时才会匹配成功。例如,(?<!a)b
表示匹配"ba",但不包括"ab"。(?>)
:非捕获组,用于将多个表达式组合在一起,但不会捕获匹配的文本。例如,(?>abc|def)
表示匹配"abc"或"def",但不会捕获匹配的文本。
这些零宽断言可以在Java爬虫中用于更精确地匹配和提取网页内容。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String html = "<div>Hello, <span>world</span>!</div>";
String regex = "<div>(?:.*?)<span>(.*?)</span>(?:.*?)</div>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(html);
if (matcher.find()) {
System.out.println(matcher.group(1)); // 输出:world
}
}
}
在这个示例中,使用正则表达式<div>(?:.*?)<span>(.*?)</span>(?:.*?)</div>
来匹配HTML中的<div>
标签内的文本内容。其中,(?:.*?)
是非捕获组,用于匹配任意字符但不捕获匹配的文本;(.*?)
是捕获组,用于匹配任意字符并捕获匹配的文本。通过使用零宽断言,我们可以精确地提取出<span>
标签内的文本内容。
贪婪爬取和非贪婪爬取
Java贪婪爬取和非贪婪爬取是正则表达式中两种不同的匹配方式。
-
贪婪爬取:默认情况下,正则表达式会尽可能多地匹配字符。例如,对于字符串"abcabc",使用正则表达式"a.c"进行匹配,会匹配整个字符串"abcabc",而不是单独的"abc"。这是因为"."和""的组合表示匹配任意数量的任意字符,而"*"是贪婪的,会尽可能多地匹配字符。
-
非贪婪爬取:在正则表达式中,可以在量词后面加上"?"来表示非贪婪匹配。例如,对于字符串"abcabc",使用正则表达式"a.?c"进行匹配,会匹配单独的"abc",而不是整个字符串"abcabc"。这是因为"."和"?"的组合表示匹配任意数量的任意字符,但"*?"是非贪婪的,会尽可能少地匹配字符。
在Java爬虫中,可以根据需要选择使用贪婪爬取或非贪婪爬取。如果需要提取更多的信息,可以使用贪婪爬取;如果只需要提取部分信息,可以使用非贪婪爬取。
代码示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String html = "<div>Hello, <span>world</span>!</div>";
// 贪婪爬取
String regex1 = "<div>(.*?)<span>(.*?)</span>(.*?)</div>";
Pattern pattern1 = Pattern.compile(regex1);
Matcher matcher1 = pattern1.matcher(html);
if (matcher1.find()) {
System.out.println(matcher1.group()); // 输出:<div>Hello, <span>world</span>!</div>
}
// 非贪婪爬取
String regex2 = "<div>(.*?)<span>(.*?)</span>(.*?)</div>?";
Pattern pattern2 = Pattern.compile(regex2);
Matcher matcher2 = pattern2.matcher(html);
if (matcher2.find()) {
System.out.println(matcher2.group()); // 输出:<div>Hello, <span>world</span>!</div>
}
}
}
在这个示例中,使用正则表达式<div>(.*?)<span>(.*?)</span>(.*?)</div>
和<div>(.*?)<span>(.*?)</span>(.*?)</div>?
分别进行贪婪爬取和非贪婪爬取。在贪婪爬取中,正则表达式会尽可能多地匹配字符,而在非贪婪爬取中,正则表达式会尽可能少地匹配字符。通过比较两种爬取方式的结果,可以看出它们的区别。
split方法
Java正则表达式split方法是一个字符串方法,用于将字符串按照指定的正则表达式进行分割,返回一个包含分割后子字符串的数组。
语法:
public String[] split(String regex)
参数:
- regex:正则表达式,用于指定分隔符。
返回值:
- 返回一个包含分割后子字符串的数组。
代码示例:
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String text = "Hello, World! 123";
// 使用逗号和空格作为分隔符
String[] result = Pattern.compile("[, ]").split(text);
for (String s : result) {
System.out.println(s);
}
// 输出:
// Hello
// World!
// 123
// 使用数字作为分隔符
result = Pattern.compile("\\d+").split(text);
for (String s : result) {
System.out.println(s);
}
// 输出:
// Hello, World!
//
}
}
replaceAll方法
Java正则表达式replaceAll方法是一个字符串方法,用于将字符串中匹配指定正则表达式的子字符串替换为指定的新字符串。
语法:
public String replaceAll(String regex, String replacement)
参数:
- regex:正则表达式,用于指定需要替换的子字符串。
- replacement:新字符串,用于替换匹配到的子字符串。
返回值:
- 返回一个新的字符串,其中所有匹配到的子字符串都被替换为指定的新字符串。
示例:
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String text = "Hello, World! 123";
// 将所有数字替换为"*"
String result = Pattern.compile("\\d+").matcher(text).replaceAll("*");
System.out.println(result); // 输出:Hello, World! ***
}
}