找到后续的数字行(由非字母字符分隔)并计算它们

时间:2016-03-11 16:36:02

标签: java regex

我想知道如何使用java regex实现以下场景:

  • 在字符串中查找所有未被字母字符分隔的后续数字,计算它们,如果位数在4到5之间(包括5个),则将其替换为"*"

示例:

  • "0000"将成为"****"
  • "any text 000 00 more texts"将成为"any text ***** more texts" ..请注意空格已删除
  • "any text 000 00 more texts 00"将成为"any text ***** more texts 00"

  • "any text 000 00 more texts 00 00"将成为"any text ***** more texts ****"

  • "any text 00-00 more texts 00_00"将成为"any text **** more texts ****"

要查找我尝试过的数字:

  • (\d*)(?=[^a-bA-Z]*)

  • (\d*)([^a-bA-Z])(\d*)

  • (\d*)([^a-bA-Z])(\d*)

但即使匹配案例也行不通。

我需要更多地了解如何进行正则表达式操作。

4 个答案:

答案 0 :(得分:1)

以下是您可以尝试的方法:

s = s.replaceAll ("\\d{5}", "*****").replaceAll("\\d{4}", "****")
for (int i = 1; i < 5; i++) {
    s = s.replaceAll("(\\d{" + i + "})([^A-Za-z]*)(\\d{" + (5 - i) + "})", "*****");
}
for (int i = 1; i < 4; i++) {
    s = s.replaceAll("(\\d{" + i + "})([^A-Za-z]*)(\\d{" + (4 - i) + "})", "****");
}

答案 1 :(得分:1)

您可以使用以下内容:

private static final Pattern p = Pattern
        .compile( "(?<!\\d[^a-z\\d]{0,10000})"
                + "\\d([^a-z\\d]*\\d){3}([^a-z\\d]*\\d)?"
                + "(?![^a-z\\d]*\\d)", Pattern.CASE_INSENSITIVE);

public static String replaceSpecial(String text) {
    StringBuffer sb = new StringBuffer();
    Matcher m = p.matcher(text);
    while (m.find()) {
        m.appendReplacement(sb, m.group(2) == null ? "****" : "*****");
    }
    m.appendTail(sb);
    return sb.toString();
}

用法演示:

System.out.println(replaceSpecial("foo 123 56 78 bar 12 32 abc 000_00"));
System.out.println(replaceSpecial("0000"));
System.out.println(replaceSpecial("any text 00 00 more texts"));
System.out.println(replaceSpecial("any text 000 00 more texts 00"));
System.out.println(replaceSpecial("any text 000 00 more texts 00 00"));
System.out.println(replaceSpecial("any text 00-00 more texts 00_00"));

结果:

foo 123 56 78 bar **** abc *****
****
any text **** more texts
any text ***** more texts 00
any text ***** more texts ****
any text **** more texts ****

思想/解释:

我们希望找到零或更多非数字但非字母字符之间的一系列数字(我们可以通过[^\\da-z]代表它们,但IMO [^a-z\\d]看起来更好所以我将使用这种形式)。这个系列的长度是4或5,我们可以写为

digit([validSeparator]*digit){3,4} //1 digit + (3 OR 4 digits) => 4 OR 5 digits

但我们需要有一些方法来识别我们是否匹配4位或5位数,因为我们需要一些方法来决定是否要用4或5个星号替换此匹配。
为此,我将尝试将第5位数字放在单独的组中,并测试该组是否为空。所以我会尝试创建像dddd(d)?这样的东西。

我是怎么想出来的

  "\\d([^a-z\\d]*\\d){3}([^a-z\\d]*\\d)?"
//                      ^^^^^^^^^^^^^^^ possible 5th digit

现在需要确保我们的正则表达式只匹配左侧或右侧未被任何数字包围的dddd(d),因为我们不想匹配任何案例,例如

d ddddd
 dddddd
 ddddd d

因此我们需要添加测试,以检查在匹配之前(或之后)是否没有数字(和有效的分隔符)。我们可以在这里使用负面观察机制,如

  • "(?<!\\d[^a-z\\d]{0,10000})" - 我使用了{0,10000}代替*,因为后台需要有一些最大长度,这使我们无法*

  • "(?![^a-z\\d]*\\d)"

所以现在我们需要做的就是组合这些正则表达式(并使其不区分大小写或代替a-z使用a-zA-Z

Pattern p = Pattern.compile( "(?<!\\d[^a-z\\d]{0,10000})"
                           + "\\d([^a-z\\d]*\\d){3}([^a-z\\d]*\\d)?"
                           + "(?![^a-z\\d]*\\d)", Pattern.CASE_INSENSITIVE);

Rest是Matcher类中appendTailappendReplacement方法的简单用法,它可以让我们动态决定使用什么来替代已建立的匹配(我试着在这里更好地解释它:{{3} })

答案 2 :(得分:1)

尝试:

(?<!\d|\d[_\W])(?=(\d|(?<=\d)[_\W]\d){4,5}(?!\d|[_\W]\d))\d|(?<=(?!^)\G)[_\W]?\d

DEMO

(?<!\d|\d[_\W])(?=(\d|(?<=\d)[_\W]\d){4,5}(?!\d|[_\W]\d))\d部分匹配数字,如果:

  • 前面没有数字或数字,后跟字母字符,
  • 后面是4-5位数字或数字和非数字的组合 按字母排序的字母
  • 4-5位/组合后,doeasn发生另一个数字或 组合

(?<=(?!^)\G)[_\W]?\d部分匹配如果:

  • 它跟随另一场比赛,但不是线的开头,
  • 是数字,或数字和非字母字符的组合,

Java中的示例:

public class RegexExample {
    public static void  main(String[] args) {
        String[] examples = {"0000","any text 000 00 more texts","any text 000 00 more texts 00",
                "any text 000 00 more texts 00 00","any text 00-00 more texts 00_00","test 00 00 00 00 00 test"};

        for(String example : examples) {
            System.out.println(example.replaceAll("(?<!\\d|\\d[_\\W])(?=(\\d|(?<=\\d)[_\\W]\\d){4,5}(?!\\d|[_\\W]\\d))\\d|(?<=(?!^)\\G)[_\\W]?\\d","*"));
        }
    }
}

带输出:

****
any text ***** more texts
any text ***** more texts 00
any text ***** more texts ****
any text **** more texts ****
test 00 00 00 00 00 test

答案 3 :(得分:0)

试试这个

(?:(?:\d[- _]*){6,})

Demo

说明:
(?<num1>\d[- _]?)(?<num2>\d[- _]?)(?<num3>\d[- _]?)(?<num4>\d)(?<num5>[- _]?\d)?:没有捕获匹配6个以上数字的行 "1-2-3-4-5-6" => no "1-2-3-4-5" => yes match 1 "1-2-3-4" => yes match 2 "1-2-3" => no "123456" => no "12345" => yes match 3 "1234" => yes match 4 "123" => no foo 123 56 78 bar :捕获4-5行数。

输入

MATCH 1
num_1   [21-23] `1-`
num_2   [23-25] `2-`
num_3   [25-27] `3-`
num_4   [27-28] `4`
num_5   [28-30] `-5`
MATCH 2
num_1   [50-52] `1-`
num_2   [52-54] `2-`
num_3   [54-56] `3-`
num_4   [56-57] `4`
MATCH 3
num_1   [119-120]   `1`
num_2   [120-121]   `2`
num_3   [121-122]   `3`
num_4   [122-123]   `4`
num_5   [123-124]   `5`
MATCH 4
num_1   [148-149]   `1`
num_2   [149-150]   `2`
num_3   [150-151]   `3`
num_4   [151-152]   `4`

输出:

*

然后用.wrapper{ width:720px; margin: 0 auto; } 替换它们:)

相关问题