Java 只匹配给定集合中出现的一个字符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23930012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 09:08:29  来源:igfitidea点击:

Matching only one occurrence of a character from a given set

javaregex

提问by Vivek Vardhan

I need to validate an input string such that validation returns trueonly if the string contains one of the special characters @ # $ %, only one, and one time at the most. Letters and numbers can be anywhere and can be repeated any number of times, but at least one number or letter should be present

我需要验证一个输入字符串,以便验证true仅在字符串包含特殊字符@#$% 之一时返回,只有一个,并且最多一次。字母和数字可以在任何地方并且可以重复任意次,但至少应出现一个数字或字母

For example:

例如:

a@ : true

一个@:真的

@a : true

@a : 真的

a@$: false

a@$: 假

a@n01 : true

a@n01 : 真

an01 : false

an01:假

a : false

一:假

@ : false

@ : 错误的

I tried

我试过

 [0-9A-Za-z]*[@#%$]{1}[0-9A-Za-z]*

I was hoping this would match one occurrence of any of the special characters. But, no. I need only one occurrence of any one in the set.

我希望这会匹配任何特殊字符的一次出现。但不是。我只需要集合中的任何一个出现一次。

I also tried alternation but could not solve it.

我也尝试过交替但无法解决它。

采纳答案by zx81

Vivek, your regex was really close. Here is the one-line regex you are looking for.

Vivek,你的正则表达式非常接近。这是您正在寻找的单行正则表达式。

^(?=.*?[0-9a-zA-Z])[0-9a-zA-Z]*[@#$%][0-9a-zA-Z]*$

See demo

演示

How does it work?

它是如何工作的?

  1. The ^and $anchors ensure that whatever we are matching is the whole string, avoiding partial matches with forbidden characters later.
  2. The (?=.*?[0-9a-zA-Z])lookahead ensures that we have at least one number or letter.
  3. The [0-9a-zA-Z]*[@#$%][0-9a-zA-Z]*matches zero or more letters or digits, followed by exactly onecharacter that is either a @, #, $or %, followed by zero or more letters or digits—ensuring that we have one special character but no more.
  1. ^$锚确保无论我们是匹配是整个字符串,避免了以后禁止文字部分匹配。
  2. (?=.*?[0-9a-zA-Z])预测先行确保我们至少有一个数字或字母。
  3. [0-9a-zA-Z]*[@#$%][0-9a-zA-Z]*匹配零个或多个字母或数字,后紧跟一个字符可以是一个@#$或者%,后跟零个或多个字母或数字,这可以确保我们有一个特殊字符,但没有更多。

Implementation

执行

I am sure you know how to implement this in Java, but to test if the string match, you could use something like this:

我相信您知道如何在 Java 中实现这一点,但是要测试字符串是否匹配,您可以使用以下内容:

boolean foundMatch = subjectString.matches("^(?=[0-9a-zA-Z]*[@#$%][0-9a-zA-Z]*$)[@#$%0-9a-zA-Z]*");

What was wrong with my regex?

我的正则表达式有什么问题?

Actually, your regex was nearly there. Here is what was missing.

实际上,您的正则表达式几乎就在那里。这是缺少的东西。

  1. Because you didn't have the ^and $anchors, the regex was able to match a subset of the string, for instance a#in a##%%, which means that special characters could appear in the string, but outside of the match. Not what you want: we need to validate the whole string by anchoring it.
  2. You needed something to ensure that at least one letter or digit was present. You could definitely have done it with an alternation, but in this case a lookahead is more compact.
  1. 因为没有^and$锚,正则表达式能够匹配字符串的一个子集,例如a#in a##%%,这意味着特殊字符可能出现在字符串中,但在匹配之外。不是你想要的:我们需要通过锚定它来验证整个字符串。
  2. 你需要一些东西来确保至少有一个字母或数字出现。您绝对可以通过交替来完成,但在这种情况下,前瞻更紧凑。

Alternative with Alternation

交替交替

Since you tried alternations, for the record, here is one way to do it:

由于您尝试了交替,为了记录,这是一种方法:

^(?:[0-9a-zA-Z]+[@#$%][0-9a-zA-Z]*|[0-9a-zA-Z]*[@#$%][0-9a-zA-Z]+)$

See demo.

演示

Let me know if you have any questions.

如果您有任何问题,请告诉我。

回答by skiwi

I hope this answer will be useful for you, if not, it might be for future readers. I am going to make two assumptions here up front: 1) You do not need regex per se, you are programming in Java. 2) You have access to Java 8.

我希望这个答案对你有用,如果没有,它可能对未来的读者有用。我将在这里预先做出两个假设:1)您本身不需要正则表达式,您正在使用 Java 进行编程。2) 您可以访问 Java 8。

This could be done the following way:

这可以通过以下方式完成:

private boolean stringMatchesChars(final String str, final List<Character> characters) {
    return (str.chars()
            .filter(ch -> characters.contains((char)ch))
            .count() == 1);
}

Here I am:

我在这里:

  1. Using as input a Stringand a List<Character>of the ones that are allowed.
  2. Obtaining an IntStream(consisting of chars) from the String.
  3. Filtering every charto only remain in the stream if they are in the List<Character>.
  4. Return trueonly if the count() == 1, that is of the characters in List<Character>, exactly one is present.
  1. 使用允许的输入 aString和 a List<Character>
  2. 获得IntStream从(由字符的)String
  3. 过滤每个char以仅保留在流中,如果它们在List<Character>.
  4. true仅当count() == 1, 即 中的字符List<Character>, 正好存在一个时才返回。

The code can be used as:

该代码可以用作:

String str1 = "a";
String str2 = "a@";
String str3 = "a@@a";
String str4 = "a#@a";
List<Character> characters = Arrays.asList('@', '#', '$', '%');

System.out.println("stringMatchesChars(str1, characters) = " + stringMatchesChars(str1, characters));
System.out.println("stringMatchesChars(str2, characters) = " + stringMatchesChars(str2, characters));
System.out.println("stringMatchesChars(str3, characters) = " + stringMatchesChars(str3, characters));
System.out.println("stringMatchesChars(str4, characters) = " + stringMatchesChars(str4, characters));

Resulting in false, true, false, false.

结果是false, true, false, false