Java正则表达式与字符集详解
1. Java正则表达式相关类
在Java J2SE 1.4版本中,引入了一些期待已久的正则表达式类,下面为你详细介绍:
-
CharSequence
:这是一个新的接口,由多个类实现,用于以抽象的方式描述字符序列。
-
Pattern
:该类将正则表达式封装在一个不可变的对象实例中。可以通过编译表达式字符串来创建实例,同时还有一些静态实用方法用于一次性匹配。
import java.util.regex.Pattern;
public class PatternExample {
public static void main(String[] args) {
// 编译正则表达式
Pattern pattern = Pattern.compile("abc");
}
}
- Matcher :它是一个状态机对象,将Pattern对象应用于输入字符序列,以在该输入中查找匹配的模式。可以从Pattern对象创建新的Matcher实例,并执行各种类型的匹配操作。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatcherExample {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("abc");
Matcher matcher = pattern.matcher("abcdef");
boolean isMatch = matcher.find();
System.out.println(isMatch);
}
}
- String :在1.4版本中,String类添加了新的正则表达式便捷方法。
Java.util.regex.Pattern支持的正则表达式语法与Perl 5的语法非常相似。
2. 字符集基础概念
在Java平台上,需要处理多种语言和字符集。Java是第一个广泛使用Unicode内部表示字符的编程语言,但这并不意味着字符处理是自动的,你仍需要了解字符映射的工作原理以及如何处理多个字符集。下面是一些与字符集和字符转码相关的术语:
-
字符集
:一组具有特定语义含义的符号,如字母“A”和符号“%”,它们在计算机发明之前就已经存在,本身没有内在的数值,也与ASCII、Unicode或计算机没有直接关系。
-
编码字符集
:为一组字符分配数值,从而得到特定的字符编码集。不同的编码字符集可能会为同一个字符分配不同的数值,字符集映射通常由标准机构确定,如US - ASCII、ISO 8859 - 1、Unicode(ISO 10646 - 1)和JIS X0201。
-
字符编码方案
:将编码字符集的成员映射到八位字节序列,定义了字符编码序列如何表示为字节序列。字符编码的数值与编码后的字节不一定相同,也不一定是一对一或一对多的关系。字符集的编码和解码原理类似于对象的序列化和反序列化。字符数据通常为了网络传输或文件存储而进行编码。大多数编码方案与单个字符集相关联,但也有可能一个编码方案处理多个字符集,例如EUC可以编码几种亚洲语言的字符。
-
Charset
:根据RFC2278的定义,它是编码字符集和字符编码方案的组合。java.nio.charset包的核心类Charset封装了这个抽象概念。
3. JDK 1.4要求支持的标准字符集
从JDK 1.4开始,每个JVM实现都必须支持一组标准字符集,具体如下表所示:
| 字符集名称 | 描述 |
| — | — |
| US - ASCII | 七位ASCII,ISO 646 - US,是Unicode字符集的基本拉丁块,即常见的美式英语字符集。 |
| ISO - 8859 - 1 | ISO - LATIN - 1,用于大多数欧洲语言的字符集,是US - ASCII的超集,包含大多数非英语的欧洲字符,字符使用八位编码。 |
| UTF - 8 | 八位UCS转换格式,由RFC 2279和Unicode标准3.0(修订版)指定。这是一种面向字节的字符编码,小于0x80的ASCII字符编码为单字节,其他字符编码为两个或更多字节。 |
| UTF - 16BE | 16位UCS转换格式,大端字节序,每个Unicode字符编码为一个双字节序列,高位字节在前。 |
| UTF - 16LE | 16位UCS转换格式,小端字节序,每个Unicode字符编码为一个双字节序列,低位字节在前。 |
| UTF - 16 | 16位UCS转换格式,字节序由可选的字节顺序标记确定。该字符集使用前导字节标记来指示编码字节流的其余部分是UTF - 16BE还是UTF - 16LE。 |
字符集名称不区分大小写。Internet Assigned Names Authority (IANA)维护着字符集名称的官方注册表,上述所有名称都是在IANA注册的标准化名称。
4. UTF - 16字符集的编码和解码
UTF - 16BE和UTF - 16LE将每个字符编码为一个双字节数值,解码器需要事先知道数据的编码方式,或者能够从编码数据流中确定字节顺序。UTF - 16编码识别一个字节顺序标记:Unicode字符\uFEFF。该标记仅在编码流的开头出现时才有特殊含义,如果在后面遇到,则根据其定义的Unicode值(零宽度、不间断空格)进行映射。小端系统可能会在前面加上\uFFFE并将流编码为UTF - 16LE。使用UTF - 16编码来添加和识别字节顺序标记,允许具有不同内部字节顺序的系统交换Unicode数据。具体的编码和解码操作如下表所示:
| 操作 | UTF - 16 | UTF - 16BE | UTF - 16LE |
| — | — | — | — |
| 编码 | 前置字节标记\uFEFF,编码为UTF - 16BE。 | 无字节标记,以大端字节序编码。 | 无字节标记,以小端字节序编码。 |
| 解码:无字节标记 | 解码为UTF - 16BE(Java的本地字节序)。 | 假设为大端字节序进行解码。 | 假设为小端字节序进行解码。 |
| 解码:标记 = \uFEFF | 丢弃标记,解码为UTF - 16BE。 | 丢弃标记,以大端字节序解码。 | 丢弃标记,以小端字节序解码。注意,解码时可能需要进行字节交换,这可能会导致运行时异常。 |
| 解码:标记 = \uFFFE | 丢弃标记,解码为UTF - 16LE。 | 丢弃标记,以大端字节序解码。注意,解码时可能需要进行字节交换,这可能会导致运行时异常。 | 丢弃标记,以小端字节序解码。 |
下面是一个示例,展示了如何使用不同的Charset实现将字符转换为字节序列:
package com.ronsoft.books.nio.charset;
import java.nio.charset.Charset;
import java.nio.ByteBuffer;
public class EncodeTest {
public static void main (String [] argv) throws Exception {
String input = "\u00bfMa\u00f1ana?";
String [] charsetNames = {
"US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16BE",
"UTF-16LE", "UTF-16"
};
for (int i = 0; i < charsetNames.length; i++) {
doEncode (Charset.forName (charsetNames [i]), input);
}
}
private static void doEncode (Charset cs, String input) {
ByteBuffer bb = cs.encode (input);
System.out.println ("Charset: " + cs.name());
System.out.println (" Input: " + input);
System.out.println ("Encoded: ");
for (int i = 0; bb.hasRemaining(); i++) {
int b = bb.get();
int ival = ((int) b) & 0xff;
char c = (char) ival;
if (i < 10) System.out.print (" ");
System.out.print (" " + i + ": ");
if (ival < 16) System.out.print ("0");
System.out.print (Integer.toHexString (ival));
if (Character.isWhitespace (c) || Character.isISOControl (c)) {
System.out.println ("");
} else {
System.out.println (" (" + c + ")");
}
}
System.out.println ("");
}
}
运行上述代码,会输出不同字符集编码后的字节序列的十六进制值。
5. Charset类详解
Charset类封装了特定字符集的不可变信息,它是抽象类,通过调用静态工厂方法forName()并传入所需字符集的名称来获取具体实例。所有Charset方法都是线程安全的,单个实例可以在多个线程之间共享。下面是Charset类的主要API:
package java.nio.charset;
import java.util.Locale;
import java.util.Set;
import java.util.SortedMap;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
public abstract class Charset implements Comparable {
public static boolean isSupported (String charsetName);
public static Charset forName (String charsetName);
public static SortedMap availableCharsets();
public final String name();
public final Set aliases();
public String displayName();
public String displayName (Locale locale);
public final boolean isRegistered();
public boolean canEncode();
public abstract CharsetEncoder newEncoder();
public final ByteBuffer encode (CharBuffer cb);
public final ByteBuffer encode (String str);
public abstract CharsetDecoder newDecoder();
public final CharBuffer decode (ByteBuffer bb);
public abstract boolean contains (Charset cs);
public final boolean equals (Object ob);
public final int compareTo (Object ob);
public final int hashCode();
public final String toString();
}
-
获取字符集实例
:
-
isSupported(String charsetName):用于确定特定字符集在当前运行的JVM中是否可用。由于可以通过Charset SPI机制动态安装新的字符集,因此对于给定字符集名称的答案可能会随时间变化。 -
forName(String charsetName):根据名称获取字符集实例。 -
availableCharsets():返回一个包含当前JVM中所有活动字符集的SortedMap。该方法可能较慢,因为需要实例化所有已知的Charset对象。如果知道要使用的字符集名称,建议使用forName()方法;只有在需要枚举所有可用字符集时,才使用availableCharsets()方法。
-
-
字符集信息获取
:
-
name():返回字符集的规范名称。 -
aliases():返回一个包含字符集别名的Set,该Set永远不会为null,但可能为空。 -
displayName()和displayName(Locale locale):提供字符集的显示名称,可用于菜单或选择框等。无参数版本使用默认的区域设置。
-
-
IANA注册信息
:
isRegistered():如果Charset对象表示的字符集在IANA注册,则返回true。注册的字符集需要满足一些要求,如规范名称应与IANA注册表中的名称匹配等。如果字符集未在IANA注册,其规范名称必须以“X - ”或“x - ”开头。
6. 字符集比较
Charset类提供了一些方法用于比较字符集:
public abstract class Charset implements Comparable {
public abstract boolean contains (Charset cs);
public final boolean equals (Object ob);
public final int compareTo (Object ob);
public final int hashCode();
public final String toString();
}
- contains(Charset cs) :判断一个字符集是否包含另一个字符集。如果一个字符集(C1)包含另一个字符集(C2),则意味着C2中可以表示的每个字符在C1中也能以相同的方式表示。该方法不进行运行时比较,只有当具体的Charset类知道给定字符集被包含时才返回true。
- equals(Object ob) :Charset实例被认为相等的条件是它们具有相同的规范名称。在JDK 1.4.0版本中,该比较是对规范名称字符串的简单比较,区分大小写,这是一个需要在未来版本中修正的bug。
通过对这些字符集相关类和方法的理解和使用,你可以更好地处理Java中的字符编码和解码问题,确保在不同的环境中正确地处理和传输字符数据。
Java正则表达式与字符集详解
7. 字符集操作示例
为了更好地理解上述字符集的操作,下面给出一些具体的使用示例。
7.1 检查字符集是否支持
import java.nio.charset.Charset;
public class CheckCharsetSupport {
public static void main(String[] args) {
String charsetName = "UTF-8";
boolean isSupported = Charset.isSupported(charsetName);
if (isSupported) {
System.out.println(charsetName + " is supported.");
} else {
System.out.println(charsetName + " is not supported.");
}
}
}
在上述代码中,使用
Charset.isSupported
方法来检查指定的字符集是否被当前JVM支持。
7.2 获取所有可用字符集
import java.nio.charset.Charset;
import java.util.Map;
import java.util.SortedMap;
public class GetAvailableCharsets {
public static void main(String[] args) {
SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
for (Map.Entry<String, Charset> entry : availableCharsets.entrySet()) {
System.out.println("Canonical Name: " + entry.getKey());
System.out.println("Aliases: " + entry.getValue().aliases());
System.out.println("----------------------");
}
}
}
此代码通过
Charset.availableCharsets
方法获取当前JVM中所有可用的字符集,并打印出它们的规范名称和别名。
8. 字符集使用流程总结
下面是一个使用字符集进行编码和解码的基本流程图:
graph TD;
A[开始] --> B[选择字符集];
B --> C{字符集是否支持};
C -- 是 --> D[获取字符集实例];
C -- 否 --> E[处理不支持情况];
D --> F[进行编码或解码操作];
F --> G[输出结果];
E --> H[结束];
G --> H[结束];
具体操作步骤如下:
1.
选择字符集
:确定需要使用的字符集名称,如“UTF - 8”、“US - ASCII”等。
2.
检查支持情况
:使用
Charset.isSupported
方法检查该字符集是否被当前JVM支持。
3.
获取实例
:如果支持,使用
Charset.forName
方法获取字符集实例。
4.
编码或解码
:使用
encode
方法进行字符编码,或使用
decode
方法进行字节解码。
5.
输出结果
:处理编码或解码后的结果。
9. 常见问题及解决方法
在使用字符集的过程中,可能会遇到一些常见问题,下面为你列举并给出解决方法:
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 字符编码错误 | 输入的字符在当前字符集中无法表示 | 选择支持该字符的字符集,如使用“UTF - 8”可以表示更多的字符。 |
| 字节顺序问题 | 在使用UTF - 16等需要字节顺序标记的字符集时,没有正确处理字节顺序 | 确保在编码时正确添加字节顺序标记,在解码时正确识别和处理字节顺序标记。 |
| 字符集不支持 | 指定的字符集在当前JVM中不可用 |
检查字符集名称是否正确,或使用
Charset.availableCharsets
方法查看可用的字符集。
|
10. 总结
字符集在Java编程中是一个非常重要的概念,尤其是在处理多语言和国际化的应用程序时。通过理解和掌握Java中的字符集相关类和方法,如
Charset
、
CharsetEncoder
和
CharsetDecoder
等,你可以更好地处理字符编码和解码问题,确保数据在不同环境中的正确传输和处理。
在实际开发中,建议遵循以下几点:
- 明确需要处理的字符范围,选择合适的字符集。
- 在进行编码和解码操作时,始终指定字符集名称,避免使用默认字符集带来的问题。
- 注意字符集的字节顺序和字节顺序标记的处理,特别是在使用UTF - 16等字符集时。
通过合理使用字符集,你可以编写出更加健壮和国际化的Java应用程序。
超级会员免费看
3118

被折叠的 条评论
为什么被折叠?



