我有一个java类(称为PhoneNumber
)来验证&处理电话号码。
我自己编写了最后一种方法(删除可选的零),但我希望它更直接一些(可能使用正则表达式来识别可选的零AND并将其删除同样的正则表达式,就像OPTIONAL_PHONE_NUMBER_CHARACTERS
部分一样)。这段代码感觉很脆弱而且不是100%正确,即使我认为它符合我的需要并涵盖了我能想到的所有单元测试。
有人能给我一个明确的例子,包括一个正确的正则表达式吗? (也欢迎其他简单的解决方案。)
private static final Pattern VALID_PHONE_NUMBER_REGEX = Pattern.compile("\\+?[0-9#*]{1,20}");
private static final Pattern OPTIONAL_PHONE_NUMBER_CHARACTERS = Pattern.compile("[\\s()/.-]");
public static boolean isValid(String phoneNumber)
{
if (phoneNumber == null || phoneNumber.isEmpty())
{
return false;
}
String compactPhoneNumber = removeOptionalCharacters(phoneNumber);
return VALID_PHONE_NUMBER_REGEX.matcher(compactPhoneNumber).matches();
}
public static String removeOptionalCharacters(String phoneNumber)
{
String phoneNumberWithoutOptionalZero = removeOptionalZero(phoneNumber);
return OPTIONAL_PHONE_NUMBER_CHARACTERS.matcher(phoneNumberWithoutOptionalZero).replaceAll("");
}
private static final String OPTIONAL_ZERO = "(0)";
private static final String OPTIONAL_ZERO_SPLIT_REGEX = Pattern.quote("(0");
public static String removeOptionalZero(String phoneNumber)
{
String[] split = phoneNumber.split(OPTIONAL_ZERO_REGEX);
if (split.length == 2 && !split[0].isEmpty())
{
return phoneNumber.replaceAll(OPTIONAL_ZERO, "");
}
return phoneNumber;
}
如您所见,我已经提取了删除可选字符的代码,以防我需要使用电话号码拨打电话。例如。 +31 12-3456-789
将转为+31123456789
。
我希望使用removeOptionalCharacters
方法工作的转化是:
+31 (0)12 3456 789 > +31123456789
+31 (012) 3456 789 > +31123456789
(0)12 3456 789 > 0123456789
(012) 3456 789 > 0123456789
为了完善它们,这些是应该成功的单元测试:
@Test
public void removeOptionalCharacters_HooksAroundOptionalZero_ZeroIsRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("+31 (0)12 3456789");
assertEquals("+31123456789", compactPhoneNumber);
}
@Test
public void removeOptionalCharacters_HooksAroundAreaCode_ZeroIsRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("+31 (012) 3456789");
assertEquals("+31123456789", compactPhoneNumber);
}
@Test
public void removeOptionalCharacters_HooksAroundOptionalZeroWithoutCountryCode_ZeroIsNotRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("(0)12 3456789");
assertEquals("0123456789", compactPhoneNumber);
}
@Test
public void removeOptionalCharacters_HooksAroundAreaCodeWithoutCountryCode_ZeroIsNotRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("(012)3456789");
assertEquals("0123456789", compactPhoneNumber);
}
PS。我认为这些测试涵盖了可选零的所有常见情况。当然还有更多的单元测试来覆盖整个事物(3456789部分还可以包括不应该删除的零,其他可选字符如 - 和+也不应该受到影响等),但为了简单起见我把他们留了出去。如果您考虑电话号码,您可以自己猜测其余部分。
答案 0 :(得分:1)
我会使用两个正则表达式。一个用于验证电话号码,另一个用于规范化电话号码,省略可选字符。 规范化正则表达式应包含独占匹配组(以|分隔)。 (0)的匹配组将是
(\(0\))
我确信有可用的Java API可以访问各个匹配组,并用您喜欢的任何内容替换它们。
正则表达式组合(0)和其他字符将是:
(\(0\))|([\\s()/.-])
仅将第一个匹配组的第一个匹配项替换为“”。 将第二组的所有匹配替换为“”
或者只是按原样保留您的代码。它是可自动记录的可读代码。正则表达式需要文档。
答案 1 :(得分:1)
经过一夜的休息,我提出了一个更简单的问题,我在问题中提供的例子:拆分正则表达式可用于替换,它甚至更好,因为它也会替换(012)区域代码的可选0(最后一个钩子将替换为所有其他可选字符)。
最重要的是,我的示例代码也删除了电话号码中的所有其他零(我认为这是Anubhava在评论中的意思)。我的新解决方案也解决了这个问题:
private static final String OPTIONAL_ZERO_REGEX = Pattern.quote("(0");
public static String removeOptionalZero(String phoneNumber)
{
String[] split = phoneNumber.split(OPTIONAL_ZERO_REGEX);
if (split.length == 2 && !split[0].isEmpty())
{ // Only remove the optional zero when preceded by a country code
return phoneNumber.replaceFirst(OPTIONAL_ZERO_REGEX, "");
}
return phoneNumber;
}
replaceFirst而不是replaceAll有点整洁,虽然我不认为它会在实践中有所作为。
其他单元测试证明它适用于非可选零:
@Test
public void removeOptionalCharacters_HooksAroundAreaCodeAndManyAdditionalZeroes_ZeroIsRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("+30 (005) 0511010");
assertEquals("+30050511010", compactPhoneNumber);
}
@Test
public void removeOptionalCharacters_HooksAroundAreaCodeWithoutCountryCodeAndManyAdditionalZeroes_ZeroIsNotRemoved()
{
String compactPhoneNumber = PhoneNumber.removeOptionalCharacters("(005)0511010");
assertEquals("0050511010", compactPhoneNumber);
}
修改强> 另一种选择:
private static final String OPTIONAL_ZERO = "(0";
private static final String OPTIONAL_ZERO_REGEX = Pattern.quote(OPTIONAL_ZERO);
public static String removeOptionalZero(String phoneNumber)
{
if (phoneNumber.indexOf(OPTIONAL_ZERO) > 0)
{ // Only remove the optional zero when preceded by a country code
return phoneNumber.replaceAll(OPTIONAL_ZERO_REGEX, "");
}
return phoneNumber;
}
PS。如果可能,最后一个示例将多次删除(0
。但是,我不认为像(0031)(012)3456789这样的情况存在,并且钩子仅用于区域代码的(部分)。如果没有,我很乐意听到它!
答案 2 :(得分:0)
可以试试这个
extension ThirdViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categoryList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! UserCategoryCollectionViewCell
cell.categoryLbl.text = categoryList[indexPath.row]
if Defaults.hasKey(.categoryListIndices) {
if (Defaults[.categoryListIndices]?.contains(indexPath.row))! {
cell.alpha = 0.1
cell.isSelected = true
} else {
cell.alpha = 1
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! UserCategoryCollectionViewCell
cell.alpha = 0.1
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let deselectedCell = collectionView.cellForItem(at: indexPath) as? UserCategoryCollectionViewCell
deselectedCell?.alpha = 1
print(deselectedCell?.isSelected)
collectionView.deselectItem(at: indexPath, animated: false)
}
}