java--正则表达式的应用:读取文件,获取其中的电话号码

1、正则表达式

正则表达式,又称 正规表示法 、 常规表示法 (英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

用到的一些特殊构造正则表达式的意义解析:


?

当该字符 紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的 贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。


.点

匹配除“\r\n”之外的任何单个字符。要匹配包括“\r\n”在内的任何字符,请使用像“[\s\S]”的模式。


(pattern)

匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。


(?:pattern)

匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。


(?=pattern)

正向肯定 预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例 如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配 “Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从 包含预查的字符之后开始。


(?!pattern)

正向否定 预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如 “Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中 的“Windows”。


(?<=pattern)

反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。


(?<!pattern)

反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。

量词使用

X { n }? X ,恰好 n 次
X { n ,}? X ,至少 n 次
X { n , m}? X ,至少 n 次,但是不超过 m 次

2、手机号码

组成

国家区域号-手机号码

手机号码格式比较固定,无非是13x xxxx xxxx或者15x xxxx xxxx再或者18x xxxx xxxx的格式。座机就比较麻烦,比如长途区号变长(3位或者4位)电话号码变长(7位或者8位)有些还需要输入分机号。

通常可以看到解决这个复杂问题的解决方案是手机号和座机号分开。座机号拆分成三段,区号,电话号码+分机号。但是为了表单看起来清爽,设计的时候给了一个“万能”的输入框,给用户输入电话号码或者手机号码。

在这样的一个需求的大前提下,用复杂的正则表达式解决验证的问题是一种快速的解决方案。

首先搞定最容易的手机号码

因为目前开放的号段是130-139, 150-159, 185-189, 180

只考虑移动电话(手机)号码的可以使用下面方法

public static void main(String[] args) {
String text = "13522158842;托尔斯泰;test2;13000002222;8613111113313";
Pattern pattern = Pattern.compile("(?<!\\d)(?:(?:1[358]\\d{9})|(?:861[358]\\d{9}))(?!\\d)");
Matcher matcher = pattern.matcher(text);
    StringBuffer bf = new StringBuffer(64);
    while (matcher.find()) {
      bf.append(matcher.group()).append(",");
    }
    int len = bf.length();
    if (len > 0) {
      bf.deleteCharAt(len - 1);
    } 

System.out.println(bf.toString());
}

只是手机号码可以匹配可以给出下面的匹配正则表达式:

(?:((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})

当我们 加上国家区域号 (86)或者(+86)或者86-或者直接是86,可以使用下面的正则表达式:

          "(?:(\\(\\+?86\\))((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})|" +
                "(?:86-?((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})|" +
                "(?:((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})"

注意 :为了最长得匹配电话号码,需要写成三句,并且相对长的需要放在前面,否则匹配到了之后,后面的就不会匹配了。

3、座机号码

组成:

国家区域号(+86等)-区号-固定电话号码-分机号

三位 区号 的部分

010, 021-029,852(香港)

因为采用三位区号的地方都是8位电话号码,因此可以写成

(010|021|022|023|024|025|026|027|028|029|852)\d{8}

当然不会这么简单,有些人习惯(010) xxxxxxxx的格式,我们也要支持一把,把以上表达式升级成

再看4位区号的城市

这里简单判断了不可能存在0111或者0222的区号,以及电话号码是7位或者8位。

最后是分机号(1-4位的数字)

(?<分机号>\D?\d{1,4})?

以上拼装起来就是:

"(?:(\\(\\+?86\\))(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
"(?:(86-?)?(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)"

4、编码实现

实现功能:读取文件,将其中的电话号码存入一个Set返回。

方法介绍:

find():尝试查找与该模式匹配的输入序列的下一个子序列。

group():返回由以前匹配操作所匹配的输入子序列。

1》、从一个字符串中获取出其中的电话号码

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 从字符串中截取出电话号码
 * @author zcr
 *
 */
public class CheckIfIsPhoneNumber
{

    /**
     * 获得电话号码的正则表达式:包括固定电话和移动电话
     * 符合规则的号码:
     *     1》、移动电话
     *         86+‘-’+11位电话号码
     *         86+11位正常的电话号码
     *         11位正常电话号码a
     *         (+86) + 11位电话号码
     *         (86) + 11位电话号码
     *     2》、固定电话
     *         区号 + ‘-’ + 固定电话  + ‘-’ + 分机号
     *         区号 + ‘-’ + 固定电话
     *         区号 + 固定电话
     * @return    电话号码的正则表达式
     */
    public static String isPhoneRegexp()
    {
        String regexp = "";

        //能满足最长匹配,但无法完成国家区域号和电话号码之间有空格的情况
        String mobilePhoneRegexp = "(?:(\\(\\+?86\\))((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})|" +
                "(?:86-?((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})|" +
                "(?:((13[0-9]{1})|(15[0-9]{1})|(18[0,5-9]{1}))+\\d{8})";

        //    System.out.println("regexp = " + mobilePhoneRegexp);
        //固定电话正则表达式

        String landlinePhoneRegexp = "(?:(\\(\\+?86\\))(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)|" +
                "(?:(86-?)?(0[0-9]{2,3}\\-?)?([2-9][0-9]{6,7})+(\\-[0-9]{1,4})?)";    

        regexp += "(?:" + mobilePhoneRegexp + "|" + landlinePhoneRegexp +")"; 

        return regexp;
    }

    /**
     * 从dataStr中获取出所有的电话号码(固话和移动电话),将其放入Set
     * @param dataStr    待查找的字符串
     * @param phoneSet    dataStr中的电话号码
     */
    public static void getPhoneNumFromStrIntoSet(String dataStr,Set<String> phoneSet)
    {
        //获得固定电话和移动电话的正则表达式
        String regexp = isPhoneRegexp();

        System.out.println("Regexp = " + regexp);

        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(dataStr); 

        //找与该模式匹配的输入序列的下一个子序列
        while (matcher.find())
        {
            //获取到之前查找到的字符串,并将其添加入set中
            phoneSet.add(matcher.group());
        }
        //System.out.println(phoneSet);
    }
}

2、读取文件并调用电话号码获取

实现方式:根据文件路径获得文件后,一行行读取,去获取里面的电话号码

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
 * 读取文件操作
 *
 * @author zcr
 *
 */
public class ImportFile
{
  /**
   * 读取文件,将文件中的电话号码读取出来,保存在Set中。
   * @param filePath	文件的绝对路径
   * @return			文件中包含的电话号码
   */
  public static Set<String> getPhoneNumFromFile(String filePath)
  {
    Set<String> phoneSet = new HashSet<String>();
    try
    {
      String encoding = "UTF-8";
      File file = new File(filePath);
      if (file.isFile() && file.exists())
      { // 判断文件是否存在
        InputStreamReader read = new InputStreamReader(
            new FileInputStream(file), encoding);// 考虑到编码格
        BufferedReader bufferedReader = new BufferedReader(read);
        String lineTxt = null;
        while ((lineTxt = bufferedReader.readLine()) != null)
        {
          //读取文件中的一行,将其中的电话号码添加到phoneSet中
          CheckIfIsPhoneNumber.getPhoneNumFromStrIntoSet(lineTxt, phoneSet);
        }
        read.close();
      }
      else
      {
        System.out.println("找不到指定的文件");
      }
    }
    catch (Exception e)
    {
      System.out.println("读取文件内容出错");
      e.printStackTrace();
    }
    return phoneSet;
  }
}

3》、测试

public static void main(String argv[])
{
  String filePath = "F:\\three.txt";
  Set<String> phoneSet = getPhoneNumFromFile(filePath);
  System.out.println("电话集合:" + phoneSet);
}

文件中数据:

结果:

电话集合:[86132221, (86)13222144332, 86-13222144332, 32434343, (+86)13222144332, 13888888888]
时间: 2024-10-15 08:26:20

java--正则表达式的应用:读取文件,获取其中的电话号码的相关文章

【工具类】JAVA 以行为单位读取文件并比对

package test20140709; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * 以行为单位读取文件并比对,显示不同行 * @author fushihua-wb * @date 2014-7-11 */ pu

JAVA 使用相对路径读取文件

转自:http://blog.csdn.net/yiluoak_47/article/details/7760385 java 使用相对路径读取文件 1.java project环境,使用java.io用相对路径读取文件的例子: *目录结构:  DecisionTree            |___src                 |___com.decisiontree.SamplesReader.java            |___resource                

[Java IO]基础:读取文件

1. 读取文件路径字符串 1.1 利用ClassLoader类方法获得文件路径 System.out.println(this.getClass().getClassLoader().getResource(".").getPath());// 得到的是项目的class文件路径 System.out.println(this.getClass().getClassLoader().getResource("").getPath());// 得到的是项目的class文

JAVA中FileReader类读取文件显示FileNotFoundException 异常的解决办法

最近在看一个生信JAVA小软件的源码,然后试着自己写一下,但是在读取文件的时候发现一直出现"找不到文件"的异常,检查了各种环境变量和目录,最后终于找到了问题所在.下面的具体的错误情况: import java.io.FileReader; public class Test{ public static void main(String[] args) { FileReader a = new FileReader("a.txt"); System.out.prin

Java 实现小工具读取文件有多少个单词

在windows 下执行如下 读取文件单词的代码在另一篇博客里传送 写完工具类后,在网上找到各种打包jar包的教程,打包好我们的读单词的代码,再新建一个记事本,名字自己命名.bat的批处理文件,类容如下: path是安装的jdk的路径,Test.jar是代码打包的包名 @echo on @echo startup set path=C:\Program Files\Java\jdk1.8.0_201\bin java -jar Test.jar pause 两个文件放在一个文件夹下,双击star

Java实现一行一行读取文件内容(进行编码处理)

// 读取文件内容public String readFile(){ String path = ""; File file = new File(path); StringBuilder result = new StringBuilder(); try{ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个B

Java程序设计---io流读取文件内容并将其逆值输出到控制台

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.OutputStreamWriter; public class 逆值 {/* *2017-07-01; */    public static void main(String[] args) throws Exception {        // TO

java实现远程储存读取文件

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException; public class tttt { public static void main(String[]

java按时间顺序读取文件夹下的所有文件

/**     * Getting files from Folder(Time Sorting by Modify time)     * @param path     * @return     */    private List<File> getFileSort(String path) {         List<File> list = getFiles(path, new ArrayList<File>());         if (list !=

java非常好用的读取文件的流的代码

学过java的都知道java中有非常多的读取文件流的操作.这个要回到javase的io操作了.io流说实话,初学者学的肯定会非常混乱,那么多流,什么输入流,输出流,什么文件流,什么字节流,等等.我在这里只能简单的给大家普及一下java的文件操作了.最后再介绍哪种方式读取文件的方法好用. 首先是File对象,File对象只是一个文件对象,比如你要操作哪个文件,就new File("传入文件的路径和名字"),要不然程序怎么能知道你要读的是哪个文件呢,或者要把哪段内容写入到哪个文件呢?,Fi