如何检查字符串是不是包含字母表中的所有字母? [复制]

Posted

技术标签:

【中文标题】如何检查字符串是不是包含字母表中的所有字母? [复制]【英文标题】:How to check if a string contains all the letters of the alphabet? [duplicate]如何检查字符串是否包含字母表中的所有字母? [复制] 【发布时间】:2017-01-08 21:05:38 【问题描述】:

我正在尝试检查一个字符串是否包含字母表中的所有字母。我创建了一个包含整个字母表的ArrayList。我将字符串转换为 char 数组,并遍历字符数组,并且对于 ArrayList 中存在的每个字符,我从中删除一个元素。最后,我试图检查Arraylist 是否为空,以查看是否所有元素都已删除。这将表明该字符串包含字母表中的所有字母。

不幸的是,代码在我从数组列表中删除元素的 if 条件内抛出 IndexOutOfBoundsException 错误

List<Character> alphabets = new ArrayList<Character>();

alphabets.add('a');
alphabets.add('b');
alphabets.add('c');
alphabets.add('d');
alphabets.add('e');
alphabets.add('f');
alphabets.add('g');
alphabets.add('h');
alphabets.add('i');
alphabets.add('j');
alphabets.add('k');
alphabets.add('l');
alphabets.add('m');
alphabets.add('n');
alphabets.add('o');
alphabets.add('p');
alphabets.add('q');
alphabets.add('r');
alphabets.add('s');
alphabets.add('t');
alphabets.add('u');
alphabets.add('v');
alphabets.add('w');
alphabets.add('x');
alphabets.add('y');
alphabets.add('z');

// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";

//Remove all the spaces
str = str.replace(" ", "");

// Convert the string to character array
char[] strChar = str.toCharArray();

for (int i = 0; i < strChar.length; i++) 

    char inp = strChar[i];

    if (alphabets.contains(inp)) 
        alphabets.remove(inp);
    


if (alphabets.isEmpty())
    System.out.println("String contains all alphabets");
else
    System.out.println("String DOESN'T contains all alphabets");

【问题讨论】:

你可以循环为int i = (int)'a'; i &lt;= 'z'而不是List 所有alphabets?像希腊语(αβγδε...ψω)和俄语(абвгд...юя)?还是您的意思是“(又名英文)字母表的所有字母”(abcde...yz)? 相关:Efficient Java language constructs to check if string is pangram? @KevinEsche:如果列表包含不相互跟随的字符,还有 "abc...xyz".toCharArray() 反过来做,循环字母并检查每个字母是否在你的字符串中。 【参考方案1】:

所有这些解决方案似乎都为相对简单的检查做了很多工作,特别是考虑到 Java 8 的流 API:

/* Your lowercase string */.chars()
    .filter(i -> i >= 'a' && i <= 'z')
    .distinct().count() == 26;

编辑:为了速度

如果您想在找到整个字母表后立即结束字符串迭代,同时仍在使用流,那么您可以在内部使用 HashSet 进行跟踪:

Set<Integer> chars = new HashSet<>();
String s = /* Your lowercase string */;
s.length() > 25 && s.chars()
    .filter(i -> i >= 'a' && i <= 'z') //only alphabet
    .filter(chars::add)                //add to our tracking set if we reach this point
    .filter(i -> chars.size() == 26)   //filter the 26th letter found
    .findAny().isPresent();            //if the 26th is found, return

这样,一旦Set 填满了所需的 26 个字符,流就会停止。

在下面的性能方面有一些(甚至仍然)更有效的解决方案,但作为个人说明,我会说不要过多地陷入过早的优化中,这样您可以在编写实际代码时获得可读性和更少的努力.

【讨论】:

+1 优雅的英语解决方案。但是对于其他语言,过滤器很快就会变得复杂得多(“pangram”的定义也是如此——如何处理字母的重音版本等) 是的,但是这有点可变,因为您可以替换不同的过滤器和字母大小。您甚至可以为此使用枚举。 :) 这个问题是长字符串可能需要很长时间 - 它会处理整个字符串,即使字符串的一小部分包含所有字母。考虑一个字符串,其前 26 个字母是字母表,然后是 100 万个其他字符。一个聪明的解决方案是在第一个 26 个字符之后停止搜索。 一些 JMH 测试将 vanilla java(来自 @hahn 的实现)与上面的流实现(AVGT,CNT 200)进行比较:流:1.118 ± 0.012 ns/op;原版:0.470 ± 0.009 ns/op @iobender 更新了我的答案,我想这有点混乱,但至少有速度优势【参考方案2】:

List.remove 按索引删除。由于 char 可以转换为 int,因此您实际上删除了不存在的索引值,即 char 'a' 等于 int 97。如您所见,您的列表没有 97 个条目。

你可以alphabet.remove(alphabets.indexOf(inp));

正如@Scary Wombat(https://***.com/a/39263836/1226744) 和@Kevin Esche (https://***.com/a/39263917/1226744) 所指出的,您的算法有更好的替代方案

【讨论】:

当您从字符串Character inp = strChar[i]; 获取字符时,提问者可以(并且应该)也使用List&lt;Character&gt; list 并使用盒装Character 这样他就避免调用错误的remove 方法,也是。 谢谢。我使用 Hashset 而不是 ArrayList,它也有效。【参考方案3】:

O(n) 解

static Set<Integer> alphabet = new HashSet<>(26);

public static void main(String[] args) 

    int cnt = 0;

    String str = "a dog is running crazily on the ground who doesn't care about the world";

    for (char c : str.toCharArray()) 
        int n = c - 'a';
        if (n >= 0 && n < 26) 
            if (alphabet.add(n)) 
                cnt += 1;
                if (cnt == 26) 
                    System.out.println("found all letters");
                    break;
                
            
        
    

【讨论】:

这就是 的答案。当我查看其他答案时,我听到脑海中的声音在尖叫“嘿!看看复杂性!” 将计数检查移到 for 循环中,这样它会在找到所有字母后立即退出,而不是不必要地检查整个字符串。【参考方案4】:

添加到@Leon 答案,创建List 并从中删除似乎完全没有必要。您可以简单地遍历'a' - 'z' 并检查每个char。此外,您正在遍历整个String 以找出每个字母是否存在。但更好的版本是循环遍历每个字母本身。这可以潜在地保护您的几次迭代。

最后一个简单的例子可能是这样的:

// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
str = str.toLowerCase();

boolean success = true;
for(char c = 'a';c <= 'z'; ++c) 
    if(!str.contains(String.valueOf(c))) 
        success = false;
        break;
    


if (success)
    System.out.println("String contains all alphabets");
else
    System.out.println("String DOESN'T contains all alphabets");

【讨论】:

简洁优雅!【参考方案5】:

正则表达式是你的朋友。此处无需使用List

public static void main(String[] args) 
    String s = "a dog is running crazily on the ground who doesn't care about the world";
    s = s.replaceAll("[^a-zA-Z]", ""); // replace everything that is not between A-Za-z 
    s = s.toLowerCase();
    s = s.replaceAll("(.)(?=.*\\1)", ""); // replace duplicate characters.
    System.out.println(s);
    System.out.println(s.length()); // 18 : So, Nope

    s = "a dog is running crazily on the ground who doesn't care about the world qwertyuioplkjhgfdsazxcvbnm";
    s = s.replaceAll("[^a-zA-Z]", "");
    s = s.toLowerCase();        
    s = s.replaceAll("(.)(?=.*\\1)", "");
    System.out.println(s);
    System.out.println(s.length()); //26 (check last part added to String)  So, Yes


【讨论】:

这是一个很酷的答案,但它实际上并没有回答代码崩溃的原因 @PierreArlaud - 你是对的。它没有回答为什么 OP 的代码会崩溃。但是,通过要求 OP 使用不同的方法来回答问题是可以的(因为将来其他人可能会来到这里并且可能会感谢所有“新方法”) 既然我们已经完成了,您认为这个解决方案在性能方面会超越使用列表的方法吗? @PierreArlaud - 好吧,这个性能可以通过使用 PatternMatcher 而不是直接使用 String#replaceAll() 来提高。但是不,这个答案不会比List / Map 方法快,其中复杂度是O(n) 如果 OP 代码在尝试自己调试后仍然崩溃,这意味着 OP 对其代码中的语句有误解。由于所有这些都是非常通用的(它不是未知的第三方 API 崩溃),如果 OP 不了解他的代码崩溃的原因,他很可能会再次遇到同样的问题。【参考方案6】:

另一个答案已经指出了异常的原因。您误用了List.remove(),因为它隐式地将char 转换为int,它称之为List.remove(int),按索引删除。

解决的方法其实很简单。您可以通过

调用List.remove(Object)
alphabets.remove((Character) inp);

其他一些改进:

    在这种情况下,您应该使用Set 而不是List。 您甚至可以使用boolean[26] 来跟踪是否出现了字母表 您不需要将字符串转换为 char 数组。只需执行str.charAt(index) 即可为您提供特定位置的角色。

【讨论】:

【参考方案7】:

一个整数变量足以存储此信息。你可以这样做

public static boolean check(String input) 
  int result = 0;    
  input = input.toLowerCase();
  for (int i = 0; i < input.length(); i++) 
    char c = input.charAt(i);
    if (c >= 'a' && c <= 'z') 
      result |= 1 << (input.charAt(i) - 'a');
    
  
  return result == 0x3ffffff;

每个位对应一个英文字母。因此,如果您的字符串包含所有字母,则结果的格式为00000011111111111111111111111111

【讨论】:

这 1. not 是否不必要地使用toCharArray 创建一个新数组(toLowerCase 是可选的,不需要时可以很容易地注释掉),2. 是否 使用奇怪的正则表达式(我的意思是,正则表达式,是认真的吗?),3. 是否对indexOf 等进行任何增加 O 复杂度的操作, 4. 不是不必要地将(装箱的!)字符存储在集合中。它最接近我将使用的解决方案 - 因此,这里唯一得到我 +1 的答案(1&lt;&lt;(c-'a') 和早期返回 if (result==0x3ffffff)return true in 循环它会还是更好)【参考方案8】:

创作怎么样

List<String> alphabets = new ArrayList <String> ();

并将值添加为字符串

然后

for (String val : alphabets)    // if str is long this will be more effecient
     if (str.contains (val) == false) 
        System.out.println ("FAIL");
        break;
     

【讨论】:

【参考方案9】:

您可以通过更改代码中的这一行来摆脱异常

char inp = strChar[i];

Character inp = strChar[i];

参考https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(java.lang.Object)

List.remove('char') 被视为List.remove('int'),这就是您收到 indexOutOfBoundsException 的原因,因为它正在检查 'a' 的ASCII 值,即 97。将变量 'inp' 转换为 Character 将调用 List.remove('Object')接口。

【讨论】:

【参考方案10】:

如果你像我一样喜欢 Java 8 流:

final List<String> alphabets = new ArrayList<>();

在用 a-z 填充字母后:

final String str = "a dog is running crazily on the ground who doesn't care about the world";
final String strAsLowercaseAndWithoutOtherChars = str.toLowerCase()
                                                     .replaceAll("[^a-z]", "");

final boolean anyCharNotFound = alphabets.parallelStream()
       .anyMatch(t -> !strAsLowercaseAndWithoutOtherChars.contains(t));

if (anyCharNotFound) 
    System.out.println("String DOESN'T contains all alphabets");
 else 
    System.out.println("String contains all alphabets");

这会将字符串转换为小写(如果您真的只是在寻找小写字母,请跳过),从字符串中删除所有不是小写字母的字符,然后检查您的 alphabets 的所有成员是否包含它们通过使用并行流在字符串中。

【讨论】:

【参考方案11】:

这是另一个简单的解决方案,它使用String.split("") 将每个字符拆分为String[] 数组,然后Arrays.asList() 将其转换为List&lt;String&gt;。然后您可以简单地调用yourStringAsList.containsAll(alphabet) 来确定您的String 是否包含字母:

String yourString = "the quick brown fox jumps over the lazy dog";

List<String> alphabet = Arrays.asList("abcdefghijklmnopqrstuvwxyz".split(""));
List<String> yourStringAsList = Arrays.asList(yourString.split(""));

boolean containsAllLetters = yourStringAsList.containsAll(alphabet);

System.out.println(containsAllLetters);

这种方法可能不是最快的,但我认为代码比提出循环和流之类的解决方案更容易理解。

【讨论】:

【参考方案12】:

做一些类似的事情

sentence.split().uniq().sort() == range('a', 'z')

【讨论】:

@Laurel 从未说过这是胡言乱语。但是侮辱在答案中没有立足之地。要么好好回答,要么继续前进。【参考方案13】:

对于 Java 8,可以这样写:

boolean check(final String input) 
    final String lower = input.toLowerCase();
    return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);

【讨论】:

【参考方案14】:

将字符串转换为小写或大写。然后遍历 A-Z 或 a-z 的等效 ascii 十进制值,如果在字符数组中找不到,则返回 false。您必须将 int 转换为 char。

【讨论】:

【参考方案15】:

我考虑过使用字符的 ASCII 码。

String toCheck = yourString.toLowerCase();
int[] arr = new int[26];
for(int i = 0; i < toCheck.length(); i++) 
    int c = ((int) toCheck.charAt(i)) - 97;
    if(c >= 0 && c < 26) 
        arr[c] = arr[c] + 1;

运行循环后,您最终会得到一个计数器数组,每个计数器代表一个字母(索引)并且它出现在字符串中。

boolean containsAlph = true;
for(int i = 0; i < 26; i++)
    if(arr[i] == 0) 
        containsAlph = false;
        break;
    

【讨论】:

这可能会导致数组的负索引,所以显然我应该编辑它以关心非拉丁字母字符。【参考方案16】:
Character inp = strChar[i]; 

使用 this 而不是 char,List remove 方法有 2 个重载方法,一个带有 object,一个带有 int。如果您传递 char,则它被视为 int 之一。

【讨论】:

以上是关于如何检查字符串是不是包含字母表中的所有字母? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何检查字符串是不是至少包含一个数字、字母和既不是数字也不是字母的字符?

Lua:如何检查字符串是不是只包含数字和字母?

检查数组是不是包含字符串但忽略该字符串中的其他字母[重复]

如何在 Java/Kotlin 中检查字符串是不是包含非 KSC5601 字母?

如何检查一个php字符串是不是只包含英文字母和数字?

如何检查字符串是不是包含从 a 到 z 的任何字母? [复制]