10.4 Java正则表达式的十大问题

本文总结了有关Java 正则表达式主要问题。由于他们经常被问到,你可能发现他们很有用。

1.如何从字符串中提取数字?

使用正则表达式的一个常见问题是将所有数字提取到整数数组中。
在Java中,\ d表示一个数字范围(0-9)。 尽可能使用预定义的类将使您的代码更易于阅读并消除畸形字符类引入的错误。 有关更多详细信息,请参阅预定义的字符类。 请注意\ d中的第一个反斜杠\。 如果您在字符串文本中使用转义构造,则必须在反斜杠之前加上另一个反斜杠,以便编译该字符串。 这就是为什么我们需要使用\ d。

List<Integer> numbers = new LinkedList<Integer>();
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(str); 
while (m.find()) {
  numbers.add(Integer.parseInt(m.group()));
}

2.如何用换行符分割Java字符串?

至少有三种不同的方法来输入新的行字符,具体取决于您正在使用的操作系统。

\r represents CR (Carriage Return), which is used in Unix
\n means LF (Line Feed), used in Mac OS
\r\n means CR + LF, used in Windows

因此,用新行分割字符串最直接的方法是:

String lines[] = String.split("\\r?\\n");

但是如果你不想要空行,你可以使用,这也是我最喜欢的方式:

String.split("[\\r\\n]+")

真正独立于系统的更健壮的方式如下。 但请记住,如果两个换行符并排放置,您仍将获得空行。

String.split(System.getProperty("line.separator"));

3. Pattern.compile()的重要性

指定为字符串的正则表达式必须首先编译到Pattern类的实例中。 Pattern.compile()方法是创建对象实例的唯一方法。 因此典型的调用序列:

Pattern p = Pattern.compile("a*b");
Matcher matcher = p.matcher("aaaaab");
assert matcher.matches() == true;

从本质上讲,Pattern.compile()用于将正则表达式转换为有限状态机(参见编译器:原理,技术和工具(第二版))。 但参与匹配的所有状态都驻留在匹配器中。 通过这种方式,模式p可以被重用。 许多匹配者可以共享相同的模式。

Matcher anotherMatcher = p.matcher("aab");
assert anotherMatcher.matches() == true;

Pattern.matches()方法被定义为只使用一次正则表达式的便利。 该方法仍然使用compile()隐式地获取Pattern的实例,并匹配一个字符串。 因此,

boolean b = Pattern.matches("a*b", "aaaaab");

相当于上面的第一个代码,但对于重复匹配,效率不高,因为它不允许重新使用编译的模式。

4.如何转义正则表达式中字符

一般来说,正则表达式使用“\”来转义结构,但是在反斜杠之前加上另一个反斜线以便Java字符串编译是很痛苦的。
用户还可以通过另一种方式将字符串文字传递给模式,例如“$ 5”。 这样$没有什么特殊含义了。

Pattern.quote("$5");

5.为什么String.split()需要管道分隔符才能被转义?

String.split()将字符串分割为给定正则表达式的匹配。 Java表达式支持影响模式匹配方式的特殊字符,称为元字符。| 是一个元字符,用于匹配几个可能的正则表达式中的单个正则表达式。 例如,A | B表示A或B。有关更多详细信息,请参阅垂直条或管道符号的交替。 因此,要使用| 作为文字,您需要通过在\ \之前添加\来避开它,例如\ |。

6.我们如何将anbn与Java正则表达式匹配?

这是所有非空字符串的语言,由一些数字a组成,后面跟着相同数量的b,如ab,aabb和aaabbb。 这种语言可以显示为上下文无关语法S→aSb | ab,因此是一种非常规的语言。

但是,Java正则表达式实现可以识别的不仅仅是普通语言。 也就是说,他们不是通过形式语言理论定义的“规则”。 使用lookahead和自我参考匹配可以实现它。 在这里,我将首先给出最终的正则表达式,然后解释一点。 为了全面的解释,我会引用你阅读我们如何匹配一个^ n b ^ n与Java正则表达式。

但是,Java正则表达式实现可以识别的不仅仅是普通语言。 也就是说,他们不是通过形式语言理论定义的“规则”。 使用lookahead和自我参考匹配可以实现它。 在这里,我将首先给出最终的正则表达式,然后解释一点。 为了全面的解释,我会引用你阅读我们如何匹配一个^ n b ^ n与Java正则表达式。

Pattern p = Pattern.compile("(?x)(?:a(?= a*(\\1?+b)))+\\1");
// true
System.out.println(p.matcher("aaabbb").matches());
// false
System.out.println(p.matcher("aaaabbb").matches());
// false
System.out.println(p.matcher("aaabbbb").matches());
// false
System.out.println(p.matcher("caaabbb").matches());

与其解释这个复杂的正则表达式的语法,我宁愿稍微说一下它是如何工作的。

1 、在第一次迭代中,它会在第一个循环处停止,然后再前进(在跳过一些之后,通过使用*)是否存在b。 这是通过使用(?:a(?= a *(\ 1?+ b)))来实现的。 如果匹配,\ 1,自我引用匹配将匹配非常内部的括号元素,这是第一次迭代中的单个b。

2、在第二次迭代中,表达式将在第二个a处停止,然后它向前看(再次跳过)以查看是否有b。 但这一次,\ 1 + b实际上相当于bb,因此必须匹配两个b。 如果是这样,\ 1将在第二次迭代后更改为bb。
3、在第n次迭代中,表达式在第n个点处停止,看看前面是否有n个bs。
通过这种方式,如果b之后的a的数量相同,则表达式可以计数as和匹配的数量。

7.如何用字符串中的单个空格替换2个或更多空格并仅删除前导空格?

String.replaceAll()用给定的替换替换与给定正则表达式匹配的每个子字符串。 “2个或更多空格”可以用正则表达式[] +表示。 因此,下面的代码将起作用。 请注意,该解决方案最终不会删除所有前导空白和尾随空白。 如果你想删除它们,你可以在管道中使用String.trim()。

String line = "  aa bbbbb   ccc     d  ";
// " aa bbbbb ccc d "
System.out.println(line.replaceAll("[\\s]+", " "));

8.如何通过正则表达式判断素数

public static void main(String[] args) {
  // false
  System.out.println(prime(1));
  // true
  System.out.println(prime(2));
  // true
  System.out.println(prime(3));
  // true
  System.out.println(prime(5));
  // false
  System.out.println(prime(8));
  // true
  System.out.println(prime(13));
  // false
  System.out.println(prime(14));
  // false
  System.out.println(prime(15));
}
 
public static boolean prime(int n) {
  return !new String(new char[n]).matches(".?|(..+?)\\1+");
}

该函数首先生成n个字符并尝试查看该字符串是否匹配。?(.. +?)\ 1+。 如果它是素数,表达式将返回false并且! 会扭转结果。

第一部分 .? 只是试图确保1不是素数。 神奇的部分是使用反向引用的第二部分。 (.. +?)\ 1+首先尝试匹配n个字符长度,然后用\ 1+重复几次。

根据定义,素数是大于1的自然数,除1和自身以外没有正数除数。 这意味着如果a = n * m那么a不是素数。 n * m可以进一步解释为“重复n次”,这正是正则表达式所做的:通过使用(.. +?)匹配n个字符长度,然后使用\ 1+重复m次。 因此,如果模式匹配,数字不是素数,否则是。 提醒一下! 会扭转结果。

9.如何分割逗号分隔的字符串,但忽略引号中的逗号?

你已经达到了正则表达式崩溃的地步。 编写简单的分离器会更好,更简洁,并且可以根据需要处理特殊情况。
或者,您可以使用switch语句或if-else模仿有限状态机的操作。 附件是一段代码。

public static void main(String[] args) {
  String line = "aaa,bbb,\"c,c\",dd;dd,\"e,e";
  List<String> toks = splitComma(line);
  for (String t : toks) {
    System.out.println("> " + t);
  }
}
 
private static List<String> splitComma(String str) {
  int start = 0;
  List<String> toks = new ArrayList<String>();
  boolean withinQuote = false;
  for (int end = 0; end < str.length(); end++) {
    char c = str.charAt(end);
    switch(c) {
    case ',':
      if (!withinQuote) {
        toks.add(str.substring(start, end));
        start = end + 1;
      }
      break;
    case '\"':
      withinQuote = !withinQuote;
      break;
    }
  }
  if (start < str.length()) {
    toks.add(str.substring(start));
  }
  return toks;
}

10.如何在Java正则表达式中使用反向引用

反向引用是Java正则表达式中另一个有用的功能。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容