java: (正则表达式,XML文档,DOM和DOM4J解析方法)
常见的XML解析技术:
1.DOM(基于XML树结构,比较耗资源,适用于多次访问XML);
2.SAX(基于事件,消耗资源小,适用于数量较大的XML);
3.JDOM(比DOM更快,JDOM仅使用具体类,而不是用接口);
4.DOM4J(非常优秀的Java,XML,API,性能优异,功能强大,开放源代码);
正则符号:
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。 ^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 $ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 * 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。 + 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 ? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。 {n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 {n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 ? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。 . 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 (pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 (?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。 (?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 (?!pattern) 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。 [xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 [^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。 [a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。 [^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。 \b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 \B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 \cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 \d 匹配一个数字字符。等价于 [0-9]。 \D 匹配一个非数字字符。等价于 [^0-9]。 \f 匹配一个换页符。等价于 \x0c 和 \cL。 \n 匹配一个换行符。等价于 \x0a 和 \cJ。 \r 匹配一个回车符。等价于 \x0d 和 \cM。 \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 \t 匹配一个制表符。等价于 \x09 和 \cI。 \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。 \w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 \W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 \xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。. \num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。 \n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 \nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 \un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。
* 字符串支持正则表达式的方法
* matches(String regex):将字符串与指定的正则表达式进行匹配,匹配成功返回true,否则返回false
*
* 电话号码的校验:3为区号+8位电话号码 4位区号+7位电话号码
* 010-12345678(01012345678) 021-12345678 027-12345678 029-12345678....
* 0371-1234567(03711234567)
* 网址校验:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
* http://www.baidu.com
* http://www.baidu.com/index.html
public class TestVertify2 { /** * 校验电话号码 * @param tel */ public static boolean checkTel(String tel){ // String regex="\\d{3,4}-?\\d{7,8}"; String regex="((0[12]\\d{1})-?\\d{8})|(0\\d{3})-?\\d{7}"; return tel.matches(regex); } /** * 校验网址:http://www.baidu.com * @param url * @return */ public static boolean checkURL(String url){ String regex="http://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?"; return url.matches(regex); } /** * 校验QQ号码 * @param qq * @return */ public static boolean checkQQ(String qq){ String regex="[1-9]\\d{4,14}"; return qq.matches(regex); } public static void main(String[] args) { // boolean is = checkTel("021-12345678"); boolean is = checkURL("http://www.baidu.com/index.html"); System.out.println(is); } }
* 字符串中支持正则表达式的常用方法:
* ***matches(String regex):将字符串与指定的正则表达式进行匹配,匹配成功返回true,否则返回false
* **replaceAll(String regex, String replacement)
* 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
* replaceFirst(String regex, String replacement)
* 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
* split(String regex)
* 根据给定正则表达式的匹配拆分此字符串。
public class TestString { public static void testReplace(){ String str="我是张三,我的QQ:12345,我的电话是:0371-1234567"; String regex="\\d+"; // str = str.replaceAll(regex, "#"); str = str.replaceFirst(regex, "#"); System.out.println(str); } public static void testSplit(){ String str="java,html,,oracle,,,mysql,,,,javascript"; String regex=",+";//可以匹配一次或多次逗号 String[] strs = str.split(regex); for (String string : strs) { System.out.println(string); } } public static void main(String[] args) { testSplit(); } }
*ava.util.regex 包主要包括以下二个类:
Pattern 类:
pattern 对象是一个正则表达式的编译表示。
Pattern 类没有公共构造方法。要创建一个 Pattern 对象,
你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
常用的方法:
compile(String regex) 将给定的正则表达式编译到模式中。
matches(String regex, CharSequence input) 编译给定正则表达式并尝试将给定输入与其匹配。
matcher(CharSequence input) 创建匹配给定输入与此模式的匹配器。
Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。
与Pattern 类一样,Matcher 也没有公共构造方法。
你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
常用方法:
find() 尝试查找与该模式匹配的输入序列的下一个子序列。
public class TestRegex { public static void testPattern(){ String content="bjsxt java is good school!"; String regex = ".*java.*"; boolean isMatcher= Pattern.matches(regex, content); System.out.println("是否包含'java'子字符串:"+isMatcher); } public static void testMatches(){ String line = "This order was placed for QT3000! OK?"; String regex = "(\\D*)(\\d+)(.*)"; //1.创建Pattern对象 Pattern pattern = Pattern.compile(regex); //2.创建Mather对象 Matcher matcher=pattern.matcher(line); if(matcher.find()){ System.out.println("第一组:"+matcher.group(0)); //找全部 System.out.println("第二组:"+matcher.group(1)); // (\\D*) System.out.println("第三组:"+matcher.group(2)); // (\\d+) System.out.println("第四组:"+matcher.group(3)); // (.*) } } public static void main(String[] args) { // testPattern(); testMatches(); } }
eg:
*网络爬虫:将网易主页源码上的超级链接提取出来。
*1.获取网页主页的源码
*2.使用正则表达式进行匹配源码,将超级链接提取
public class WebSipder { public static void main(String[] args) { try { //获取网易源码 URL url = new URL("http://www.163.com"); InputStream ips = url.openStream(); InputStreamReader isr = new InputStreamReader(ips); BufferedReader br = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); String str; while((str=br.readLine())!=null){ sb.append(str+"\n"); } // System.out.println(sb); //从源码中提取网址 http://yuedu.163.com String regex="http://\\w*\\.*\\w*\\.com"; //创建一个pattern对象(正则表达式) Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(sb); while(matcher.find()){ String address = matcher.group(); System.out.println(address); } br.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
XML文档:
<?xml version="1.0" encoding="UTF-8"?> <students> <student id="1"> <name>张三</name> <course>java</course> <score>90</score> </student> <student id="2"> <name>李四</name> <course>oracle</course> <score>80</score> </student> </students>
DTD:文档类型定义
<?xml version="1.0" encoding="UTF-8"?> <!-- DTD(文档类型定义):验证XML内容的合法性。 语法: <!DOCTYPE 根元素 [ <!ELEMENT 元素名称 (子元素名称,子元素名称,子元素名称) > <!ELEMENT 子元素名称 (#PCDATA)> <!ELEMENT 子元素名称 (#PCDATA)> <!ELEMENT 子元素名称 (#PCDATA)> ]> --> <!DOCTYPE books [ <!ELEMENT books (book+)> //必须得有空格隔开才不报错 <!ELEMENT book (name,author,price)> <!ELEMENT name (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> ]> <books> <book> <name>三国</name> <author>罗贯中</author> <price>50</price> </book> <book> <name>水浒</name> <author>施耐庵</author> <price>40</price> </book> </books>
DOM:
<?xml version="1.0" encoding="UTF-8"?> <students> <student id="1"> <name>张三</name> </student> <student id="2"> <name>李四</name> </student> </students>
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** *DOM(Document Object Model)文档对象模型 *DOM的特点: *需要一次性将xml文件加载内存中,常驻内存,对内存资源占用较大,适合多次访问的XML解析 *DOM解析的步骤 *1.创建一个解析器工厂对象 *2.创建一个解析器 *3.使用解析器对xml文件进行解析,将xml文档构成一个Document并返回 *4.以Document为基础,遍历其中的内容以获取和操作响应的节点和数据 */ public class TestDomParse { public static void main(String[] args) { //1.创建工厂解析器 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { //2.创建解析对象 DocumentBuilder db = dbf.newDocumentBuilder(); //3.将xml文档转换为Document对象 Document document = db.parse(new FileInputStream("scores.xml")); //4.以document对象为基础,获取子元素 // Element root = document.getDocumentElement();//根节点students //根据标签名称获取该标签的列表 NodeList nodeList = document.getElementsByTagName("students"); Node rootNode=nodeList.item(0);//根节点 NodeList studentNodeList = rootNode.getChildNodes();//获取父节点的子节点(student节点的集合) //遍历子节点 for (int i = 0; i < studentNodeList.getLength(); i++) { Node studentNode = studentNodeList.item(i);//获取子节点 if(studentNode.getNodeType()==Node.ELEMENT_NODE){ Element studentElement = (Element)studentNode;//student节点 String id = studentElement.getAttribute("id"); System.out.println("id="+id); NodeList subNodeList = studentElement.getChildNodes();//获取student节点的子节点列表 //遍历student的子节点列表 for (int j = 0; j < subNodeList.getLength(); j++) { Node subNode = subNodeList.item(j);//name,course,score if(subNode.getNodeType()==Node.ELEMENT_NODE){ String text = subNode.getTextContent();//获取文本节点 System.out.println(subNode.getNodeName()+"="+text); } } } } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
DOM4J:
import java.io.File; import java.util.Iterator; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * DOM4J:开源项目(针对XML进行解析和操作的开源API) * 使用DOMJ解析XML步骤: * 1.添加dom4j的类库:先将dom4_xx.jar复制到项目中,选择dom4j_xx.jar右键:build path--->add to build path * 2.指定要解析的XML文件 * 3.将XML文件转换为Document对象(文档树) * SAXReader saxReader = new SAXReader(); * Doucment document = saxReader.read(file); * 4.遍历Document中的元素,获取其属性,文本节点中内容。 * * Document中的常用方法 * getRootElement():获取文档中的根节点 * Element中的常用方法 * elementIterator():获取该元素的所有子元素 * attributeValue(String attrName):根据属性名称获取该属性的值 * getName():获取该元素的元素名称 * getText():获取该元素的文本节点 */ public class TestDom4jParse { public static void main(String[] args) { //2.指定要解析XML文件 File file = new File("scores.xml"); //3.将XML文件转换为Document文档 SAXReader saxReader = new SAXReader(); try { Document document = saxReader.read(file); //获取根节点:getRootElement() Element root = document.getRootElement();//students节点 //获取根节点的子节点 Iterator<Element> studentIter = root.elementIterator(); while(studentIter.hasNext()){ Element student = studentIter.next();//获取student节点 String id = student.attributeValue("id");//获取id属性的值 System.out.println("id="+id); //获取学生节点的子节点 Iterator<Element> subIter= student.elementIterator(); while(subIter.hasNext()){ Element subElement= subIter.next(); String name = subElement.getName();//获取元素的名称 String text = subElement.getText(); System.out.println(name+"--->"+text); } } } catch (DocumentException e) { e.printStackTrace(); } } }
DOM4J创建XML文档:
import java.io.FileWriter; import java.io.IOException; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; /** * <products> * <product id="001"> * <name>iphone8</name> * <price>1500</price> * </product> * <product id="002"> * <name>iphone8 plus</name> * <price>1600</price> * </product> * </products> * 通过dom4j生成一个xml文件 * 1.创建Document对象(空的文档数) 2.向Document对象中添加子节点和属性 3.通过XMLWriter和IO流将document写入文件中 */ public class TestDom4jWriter { public static void main(String[] args) { // 构建一个Document对象 Document document = DocumentHelper.createDocument(); // 为document对象添加根节点 Element products = document.addElement("products"); // 为products节点添加子节点 Element product = products.addElement("product"); product.addAttribute("id", "001");// 为product添加属性 Element name = product.addElement("name"); name.setText("iphone8");// 设置name的文本节点 Element price = product.addElement("price"); price.setText("1500"); // 为products节点添加子节点 Element product2 = products.addElement("product"); product2.addAttribute("id", "002");// 为product添加属性 Element name2 = product2.addElement("name"); name2.setText("iphone8 plus");// 设置name的文本节点 Element price2 = product2.addElement("price"); price2.setText("1500"); try { //将document对象写入文件中 FileWriter fw = new FileWriter("test.xml"); OutputFormat ops = OutputFormat.createPrettyPrint(); ops.setEncoding("GBK"); ops.setIndent(true);//设置缩进 XMLWriter xmlWriter = new XMLWriter(fw,ops); xmlWriter.write(document);//将document写入到文件中 xmlWriter.flush(); xmlWriter.close(); System.out.println("写入完成!"); } catch (IOException e) { e.printStackTrace(); } } }
DOM4J将所解析XML的文档封装在类中:
package cn.zzsxt.homework; /** * 用于封装xml解析出的servlet节点中的信息 *<servlet> <servlet-name>LoginServlet</servlet-name> <url-pattern>/LoginServlet</url-pattern> </servlet> * @author Administrator:实体类(封装数据) * */ public class ServletBean { private String servletName;//封装servlet-name中节点中的值 private String urlPattern;//封装url-pattern节点中的值 public ServletBean(){ } public ServletBean(String servletName,String urlPattern){ this.servletName=servletName; this.urlPattern=urlPattern; } public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public String getUrlPattern() { return urlPattern; } public void setUrlPattern(String urlPattern) { this.urlPattern = urlPattern; } }
package cn.zzsxt.homework; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public class Homework { /** * 生成xml的方法 */ public static void writer(){ //1.创建一个Document对象(空文档树) Document document = DocumentHelper.createDocument(); //2.为文档添加节点 Element webapps = document.addElement("webapps"); //3.为webapps节点添加子节点 Element servlet1 = webapps.addElement("servlet"); Element servlet2 = webapps.addElement("servlet"); //4.为servlet节点添加子节点 Element servletName1= servlet1.addElement("servlet-name"); Element urlPattern1= servlet1.addElement("url-pattern"); //5.为servlet节点添加文本 servletName1.setText("LoginServlet"); urlPattern1.setText("/LoginServlet"); Element servletName2= servlet2.addElement("servlet-name"); Element urlPattern2= servlet2.addElement("url-pattern"); servletName2.setText("IndexServlet"); urlPattern2.setText("/IndexServlet"); //6.将Document写入文件 try { FileWriter fw = new FileWriter(new File("web.xml")); OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("UTF-8");//设置编码集 format.setIndent(true);//设置缩进 XMLWriter xmlWriter = new XMLWriter(fw, format); xmlWriter.write(document); xmlWriter.close(); System.out.println("web.xml已经生成!"); } catch (IOException e) { e.printStackTrace(); } } /** * 解析web.xml,将servlet子节点中的信息封装到ServletBean对象中,并将其加入到List中进行返回。 * @return */ public static List<ServletBean> parseXML(){ List<ServletBean> list = new ArrayList<ServletBean>(); //解析XML文件 SAXReader saxReader = new SAXReader(); try { Document document = saxReader.read(new File("web.xml")); //获取根节点 Element webapps = document.getRootElement(); Iterator<Element> servletIter= webapps.elementIterator(); while(servletIter.hasNext()){ Element servlet = servletIter.next();//servlet节点 Iterator<Element> servletSubIter = servlet.elementIterator(); //创建一个ServletBean对象,用于封装servlet子节点中的信息 ServletBean servletBean = new ServletBean(); while(servletSubIter.hasNext()){ Element subElement= servletSubIter.next();//servlet-name和url-pattern String elementName = subElement.getName(); //将servlet-name节点中文本封装到ServletBean的servletName属性中 if(elementName.equals("servlet-name")){ String servletName = subElement.getText(); servletBean.setServletName(servletName); }else if(elementName.equals("url-pattern")){ //将url-pattern节点中文本封装到ServletBean的urlPattern属性中 String urlPattern =subElement.getText(); servletBean.setUrlPattern(urlPattern); } } //将ServletBean添加到List集合中 list.add(servletBean); } } catch (DocumentException e) { e.printStackTrace(); } return list; } public static void main(String[] args) { // writer(); List<ServletBean> list = parseXML(); for (ServletBean servletBean : list) { System.out.println(servletBean.getServletName()+"----"+servletBean.getUrlPattern()); } } }