我正在尝试计算每个字符出现在字符串中的次数,但是程序有几个问题打印出大写/小写的不同计数以及不打印出来对于不显示的字符,计数为0.
所需的输出应该是......
A = 0
B = 1
C = 2
...
X = 0
Y = 1
Z = 2
以及列出0-9发生的次数或未发生的次数。我已经找到了一种工作方法来防止大写/小写字符不在一起计算(p = 1,P = 1),但不确定它是否是最有效的。但主要的问题是让程序打印出未出现在字符串中的字符。我遇到的大多数其他帖子都涉及用户检查某个角色出现的次数而不是所有角色。
到目前为止我的代码是
import java.util.*;
import java.io.*;
public class LetterCount {
public static void main(String[] args) throws FileNotFoundException{
String myInput;
Scanner fileIn = new Scanner(new File("input_test"));
myInput = fileIn.nextLine();
myInput=charAdjust(myInput);
charCounter(myInput);
fileIn.close();
}
public static String charAdjust(String s) throws FileNotFoundException {
String str;
Scanner fileIn = new Scanner(new File("input_test"));
str=fileIn.nextLine();
System.out.println("-----------");
fileIn.close();
return (str.toUpperCase());
}
public static String charCounter(String str) {
int[]counter = new int[(int) Character.MAX_VALUE];
for (int i=0; i<str.length(); i++){
char charAt = str.charAt(i);
counter[(int) charAt]++;
}
for (int i=0; i<counter.length; i++) {
if (counter[i] > 0)
System.out.println((char)i + " = " + counter[i]);
}
return str;
}
}
答案 0 :(得分:0)
没有简单的方法可以做到这一点。严格来说,为了确定字母表中所有字母的数量,你必须知道字母表是什么。
例如,您显然是说英语的人,因此根据您在帖子中定义的规则[A-Za-z0-9]
。但想象你是俄罗斯人;你的字母表会改变,你的程序需要以不同的方式运作。你知道那些字母是什么的唯一方法就是定义它们。
如果你只是谈论英语,而只是[A-Za-z0-9]
那么它会变得更简单一些。 [A-Za-z0-9]
以ASCII表示,可以表示为数字值,您可以清楚地知道这些数据值。
从代码段尝试此操作的方式是关于最有效的方法 - 一两点警告。如果你以任何方式,形状或形式了解C,那么你就知道我要解释的是什么,但为了完整,无论如何我都会描述它。基本上,你说你有一段内存从内存地址N开始。地址是一个字符的大小(在Java中应该是2个字节,而不是在C中的1个字节 - 尽管这是用Java抽象出来的并且不是严格的2个字节,它通常是我的知识)乘以数组的索引数(在您的情况下,它是2 ^ 16或65536索引)。当你说array[N]
时,它很聪明地知道要准确地跳到N * size_of_char的内存地址并获得该地址的值。这是最快的。
你的逻辑部分落后一点,就是你的缓冲区,如上一节所暗示的那样,65536指数很大,这显然比你所描述的要求更加关注。但是,这可以通过一些简单的逻辑来减轻,当您尝试处理指标时,只读取您关心的指数。换句话说,只读取48-57
(0-9),65-90
(A-Z)和97-122
(a-z)的索引。
下一个最好的方法是使用Java Collection,例如HashMap
。这远比你使用的数组效率低得多,所以我不推荐它。
编辑:我不清楚你是否试图将a-z
和A-Z
的字符数一起聚合,或者你是否试图单独计算它们。将它们放在一起或分开并不困难。正如有人在评论中提到的那样,您可以使用算术从ASCII字符中获取大写/小写字母,这非常快(而且非常快,我的意思是单个CPU周期)。
编辑2:在审核时,似乎我不一定回答你的所有问题。要打印出未出现在字符串中的字符,您只需从数字48-57
(0-9),65-90
(AZ)和97-122
中读取数组( az)并打印出值。初始化数组时,它会初始化为无效值。在您的情况下,您使用int
数组。 int
是一个原语,原始版本的零值转换为零值。 int
,short
,byte
和char
表示0,boolean
表示错误,long
表示0L,对于double
和float
,这意味着0F。换句话说,您不必执行任何明确的操作来获取未出现在String中的字符。只需读取与您关注的字母相关的所有索引,如果它不是您的字符串的一部分,它将为您提供“零”(或零)值。
答案 1 :(得分:0)
一些提示:
现在不要过分担心进一步提高效率 - 只需循环遍历字符串中的字符一次就可以做正确的事情。一些初学者会为他们正在搜索的每个字符读取字符串一次,使其变得非常慢,并且你已经避免了这一点。
还有其他一些用于迭代字符串的技术,例如: StringReader
,但您很快就会遇到它们,charAt()
现在还可以。 (事实上,String.charAt()
速度超快 - 它是一种廉价的阵列查找。其他选项将具有相同的速度,但可能更具表现力,并且更适应其他角色来源,例如作为文件或网络流。)
你不能避免两个循环:一次通过输入字符串来收集你的计数,然后另一个通过counter
数组来输出结果。
您首先使用toUpperCase
的策略是正常的,也很常见。对于非常长的输入,最好在遇到它时对每个char进行大写:
char charAt = Character.toUpperCase(str.charAt(i));
这是因为在幕后,String.toUpperCase()
(当然)循环输入字符串,所以你要添加第三个循环,其中两个就足够了。但是,如果你知道输入并不大,那真的无关紧要。
由于您只对A-Z和0-9感兴趣,因此您可以使用大小为36的counter
数组 - 如果为其他&#39;保留一个广告位,则可以使用37。您需要编写一个方法将char转换为其索引:
int charToIndex(char c) {
char upper = Character.toUpperCase(c);
if(upper >= 'A' && upper <= 'Z') {
// returns 1 for 'A' ... 26 for 'Z'
return (upper - 'A') + 1;
}
if(upper >= '0' && upper <= '9') {
// returns 27 for '0' ... 37 for '9'
return 27 + (upper - '0');
}
return 0; // meaning 'other'
}
现在要输出你的计数,你只需要遍历这个小数组,输出每一项。您需要编写另一种方法将索引转换回可打印的字母/数字。
请注意,这仅适用于ASCII字母和数字。在Unicode世界中,事情变得更加复杂,其中有数百个其他字符,包括表情符号,非罗马字母,甚至符号与拉丁字母表中的字母完全相同,但代码不同。
答案 2 :(得分:0)
创建一个容量为123个元素的int数组(从'0'
到'9'
和'A'
到'Z'
和'a'
到'z'
,最高值是'z'
,即122)。
迭代每个字符并将其用作计数器中的索引。 NOT 大写任何东西 - 这是浪费时间。
打印字母时,只需要从索引65到90(这些是大写字母)。您是否知道大写与小写对应的分隔是32?换句话说,您可以通过执行类似'a'
的操作将'A'
和counter['A'] + counter['A' + 32]
放在一起。不需要大写任何东西。
打印数字时,您只需要从索引48转到57。
public static void main(String[] args) {
String input = "sjdSaaASDB12bbBBB555BbbbjsdajdasJDa51hkajsdJASDHKjasd2233haksjdDAKSJD!!!!";
int[] letters = new int[123]; // Because from '0' to 'z', the highest is 122.
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);
if (c <= 122) letters[c] += 1;
}
System.out.println("LETTER COUNT:");
for (int i = 'A'; i < 'Z'; ++i) {
if ((letters[i] + letters[i + 32]) > 0) System.out.println((char)i + " -> " + (letters[i] + letters[i + 32]));
}
System.out.println("NUMBER COUNT:");
for (int i = '0'; i < '9'; ++i) {
System.out.println((char)i + " -> " + letters[i]);
}
}
答案 3 :(得分:0)
HashMap可能不是最便宜的解决方案,但如果有人对此不太在意,则至少有一个循环就可以实现,并且很简单。希望这对某人有帮助。
public static void charOccurence(String string) {
// create a char array out of your string
char[] chs = string.toCharArray();
// create a map for storing your character and count pairs
HashMap<Character, Integer> map = new HashMap<>();
// loop trough using the string length
for (int i = 0; i < string.length() ; i++) {
// if you already have the letter stored simply add one to the count
if (map.containsKey(chs[i])) {
int count = map.get(chs[i]) + 1;
map.put(chs[i], count);
// else add your letter for the first time with the count of 1
} else {
map.put(chs[i], 1);
}
}
// print results
System.out.println(map);
}
答案 4 :(得分:-1)
HashMap可能是Java中这个问题最简单的实现。
public static String charCounter(String str) {
// Initialize counter HashMap with 0 value counts for desired characters
HashMap<Character, Integer> counter = new HashMap<Character, Integer>();
String indexes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i=0; i<indexes.length;i++){
counter.put(indexes.charAt(i), 0);
}
// Update HashMap by incrementing for each character in the string
for (int i=0; i<str.length(); i++){
char charAt = Character.toUpperCase(str.charAt(i));
int count = counter.containsKey(charAt) ? counter.get(charAt) : 0;
counter.put(charAt, count+1)
}
// Print out the counts
for (int i=0; i<indexes.length; i++) {
char index = Character.toUpperCase(indexes.charAt(i));
int count = counter.get(index);
if (counter.get(index) >= 0)
System.out.println(index + " = " + count);
}
return str;
}