regex

nx7onnlm  于 2021-07-03  发布在  Java
关注(0)|答案(3)|浏览(246)

我需要编写一个正则表达式,用以下条件验证电话号码:
如果输入少于7位,则按原样返回。否则,如果第一个字符是1或0,请删除它。如果我们还没有返回,并且数字小于10位,请返回它。如果大于等于10位,则返回最后7位。
这是从编码的条件语句转换而来的性能关键代码,因此理想情况下可以在单个regex中完成。我设法拼凑了一些东西,使我接近,但我有一些困难,满足所有的标准,而不是进一步打破东西。
(因为这里有很多东西,所以空格只是用来分隔东西)。

var pattern = Pattern.compile("(?<=\A[01]?) ([0-9]{1,9}) (?![0-9]) | (?:[01]?) (?<=\A[01]?) (?:[0-9]{3,}) ([0-9]{7}) (.*)", "$1$2");
return pattern.replaceAll(phoneNum);

它通过了我给它的所有测试字符串,除了它不会像应该的那样删除0或1,如果它们作为长度为7+的字符串的第一个字符存在的话。

// Returns input as-is if fewer than 7 digits
    555123  --> 555123    Success

// If 7+ digits remove the first character if it is a 1 or 0
   1234567  --> 234567    Failure, returned 1234567

// If we haven't returned yet and the number is < 10 digits, return
   5551212  --> 5551212   Success

// If it's >= 10 digits, return the last 7
5551234567  --> 1234567   Success
mkshixfv

mkshixfv1#

下面是if版本,正如注解中所建议的,我还将您的测试添加为单元测试:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class SomeClass {

    public String correctPhoneNumber(String number) {
        if (number.length() >= 7 && (number.startsWith("0") || number.startsWith("1"))) {
            return number.substring(1);
        }
        if (number.length() >= 10) {
            return number.substring(number.length() - 7);
        }
        return number;
    }

    @Test
    void correctPhoneNumberTest() {
        SomeClass objectToTest = new SomeClass();

        assertEquals("555123", objectToTest.correctPhoneNumber("555123"));
        assertEquals("234567", objectToTest.correctPhoneNumber("1234567"));
        assertEquals("5551212", objectToTest.correctPhoneNumber("5551212"));
        assertEquals("1234567", objectToTest.correctPhoneNumber("5551234567"));
    }

}
kkih6yb8

kkih6yb82#

java不是我的强项,但正如人们提到的,regex可能不是解决您问题的正确方法。如果您仍然对正则表达式感兴趣,我认为以下内容涵盖了您的所有标准:

^(?:(?=\d{7,9}$)[01]?|\d*(?=\d{7}$)|)(\d+$)

查看在线演示 ^ -开始串ancor。 (?: -打开非捕获组。 (?=\d{7,9}$ -当有7-9位数字到字符串末尾ancor时,一个肯定的向前看来Assert位置。 [01]? -可以选择捕获0或1。 | -或: \d* -捕获尽可能多的数字,但直到: (?=\d{7}$) -正向向前看7位直到结束字符串ancor。 | -或者:不匹配。 ) -关闭非捕获组。 (\d+$) -捕获第一个捕获组中的所有剩余数字,直到结束字符串ancor。

6za6bjd0

6za6bjd03#

用lambda替换all就足够了,缺点是lambda有点慢,但是regex更快。它更易于维护,当然对于现实世界的业务逻辑来说。只需将结果计时在一个微基准中。

var pattern = Pattern.compile("\\b(\\d+)\\b");
return pattern.matcher(phoneNum).replaceAll(mr -> {
    String digits = mr.group(1);
    if (digits.length() < 7) { // Or better \\d{7, 20}
        return digits;
    }
    if (digits.startsWith("0") || digits.startsWith(1)) { // Can be optimized
        digits = digits.substring(1);
    }
    if (digits >= 10) {
        digits = digits.substring(digits.length() - 7);
    }
    return digits;
});

您的测试用例应该保持为单元测试,因为这样的业务规则往往会“稍微”改变——特别是如果您喜欢单个regex的话。

相关问题