什么是最简单/最好/最正确的方法来遍历Java中的string的字符?
StringTokenizer
? 将String
转换为一个char[]
并迭代呢? 别的东西?
我使用for循环迭代string,并使用charAt()
来获取每个字符来检查它。 由于String是用数组实现的,所以charAt()
方法是一个常量操作。
String s = "...stuff..."; for (int i = 0; i < s.length(); i++){ char c = s.charAt(i); //Process char }
那就是我会做的。 对我来说似乎是最简单的。
就正确性而言,我不相信在这里存在。 这一切都是基于你的个人风格。
两个选项
for(int i = 0, n = s.length() ; i < n ; i++) { char c = s.charAt(i); }
要么
for(char c : s.toCharArray()) { // process c }
第一个可能更快,然后第二个可能更可读。
注意这里描述的大多数其他技术如果处理BMP(Unicode 基本多语言平面 )以外的字符,即在u0000-uFFFF范围之外的代码点 ,则会发生故障。 这只会发生很less,因为在这之外的代码点大多被分配到死语言。 但是除此之外还有一些有用的字符,例如用于math符号的一些代码点,还有一些用于用中文编码正确的名称。
在这种情况下,你的代码将是:
String str = "...."; int offset = 0, strLen = str.length(); while (offset < strLen) { int curChar = str.codePointAt(offset); offset += Character.charCount(curChar); // do something with curChar }
Character.charCount(int)
方法需要Java 5+。
来源: http : //mindprod.com/jgloss/codepoint.html
我同意StringTokenizer在这里是矫枉过正的。 其实我试了上面的build议,花时间了。
我的testing非常简单:创build一个包含大约一百万个字符的StringBuilder,将其转换为一个string,然后使用charAt()/将其转换为一个字符数组/一个CharacterIterator一千次后遍历每个string(当然,确保在string上做一些事情,以便编译器不能优化整个循环:-))。
我的2.6 GHz Powerbook(这是一个mac :-))和JDK 1.5的结果:
- testing1:charAt +string – > 3138毫秒
- testing2:将string转换为数组 – > 9568毫秒
- testing3:StringBuilder charAt – > 3536msec
- testing4:CharacterIterator和string – > 12151毫秒
由于结果显着不同,最直接的方式似乎也是最快的。 有趣的是,StringBuilder的charAt()似乎比String的稍慢一些。
顺便说一句,我build议不要使用CharacterIterator,因为我认为它的滥用“\ uFFFF”字符作为“迭代结束”一个非常糟糕的黑客。 在大项目中,总有两个人为了两个不同的目的而使用相同的破解方式,代码崩溃真的很神秘。
这是一个testing:
int count = 1000; ... System.out.println("Test 1: charAt + String"); long t = System.currentTimeMillis(); int sum=0; for (int i=0; i<count; i++) { int len = str.length(); for (int j=0; j<len; j++) { if (str.charAt(j) == 'b') sum = sum + 1; } } t = System.currentTimeMillis()-t; System.out.println("result: "+ sum + " after " + t + "msec");
有一些专门的课程:
import java.text.*; final CharacterIterator it = new StringCharacterIterator(s); for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { // process c ... }
如果你的类path上有番石榴 ,以下是一个非常可读的select。 番石榴甚至有一个相当明智的自定义List实现这种情况下,所以这不应该是低效的。
for(char c : Lists.charactersOf(yourString)) { // Do whatever you want }
更新:正如@Alex指出的那样,在Java 8中还有CharSequence#chars
要使用。 即使types是IntStream,所以它可以被映射为字符,如:
yourString.chars() .mapToObj(c -> Character.valueOf((char) c)) .forEach(c -> System.out.println(c)); // Or whatever you want
如果你需要迭代一个String
的代码点(见这个答案 ),一个更简单/更可读的方法是使用Java 8中添加的CharSequence#codePoints
方法:
for(int c : string.codePoints().toArray()){ ... }
或直接使用stream而不是for循环:
string.codePoints().forEach(c -> ...);
还有CharSequence#chars
如果你想要一个CharSequence#chars
stream(虽然它是一个IntStream
,因为没有IntStream
)。
我不会使用StringTokenizer
因为它是传统的JDK中的一个类。
javadoc说:
StringTokenizer
是一个遗留的类,为了兼容性的原因被保留下来,尽pipe在新代码中不鼓励使用它。 build议任何需要此function的人使用String
或java.util.regex
包的拆分方法。
请参阅Java教程:string 。
public class StringDemo { public static void main(String[] args) { String palindrome = "Dot saw I was Tod"; int len = palindrome.length(); char[] tempCharArray = new char[len]; char[] charArray = new char[len]; // put original string in an array of chars for (int i = 0; i < len; i++) { tempCharArray[i] = palindrome.charAt(i); } // reverse array of chars for (int j = 0; j < len; j++) { charArray[j] = tempCharArray[len - 1 - j]; } String reversePalindrome = new String(charArray); System.out.println(reversePalindrome); } }
将长度放入int len
并使用for
循环。
StringTokenizer完全不适合将string分解为单个字符的任务。 使用String#split()
你可以通过使用一个不匹配的正则expression式来轻松完成,例如:
String[] theChars = str.split("|");
但StringTokenizer不使用正则expression式,并且没有分隔符string可以指定匹配字符之间的任何内容。 有一个可爱的小黑客可以用来完成同样的事情:使用string本身作为分隔符string(使每个字符在它的分隔符),并让它返回分隔符:
StringTokenizer st = new StringTokenizer(str, str, true);
但是,我只是为了解雇他们而提到这些select。 这两种技术都将原始string分解为一个字符的string而不是char基元,并且都以对象创build和string操作的forms涉及大量的开销。 将它与在for循环中调用charAt()相比,几乎没有开销。
详细阐述这个答案和这个答案 。
上面的答案指出了许多这种不通过代码点值迭代的解决scheme的问题 – 它们在任何代理字符时都会遇到麻烦。 java文档也在这里概述了这个问题(请参阅“Unicode字符表示”)。 无论如何,这里有一些代码使用补充的Unicode集中的一些实际的代理字符,并将它们转换回string。 请注意.toChars()返回一个字符数组:如果你正在处理代理,你必须有两个字符。 这个代码应该适用于任何 Unicode字符。
String supplementary = "Some Supplementary: 𠜎𠜱𠝹𠱓"; supplementary.codePoints().forEach(cp -> System.out.print(new String(Character.toChars(cp))));
这个示例代码将帮助你!
import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; public class Solution { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 10); map.put("b", 30); map.put("c", 50); map.put("d", 40); map.put("e", 20); System.out.println(map); Map sortedMap = sortByValue(map); System.out.println(sortedMap); } public static Map sortByValue(Map unsortedMap) { Map sortedMap = new TreeMap(new ValueComparator(unsortedMap)); sortedMap.putAll(unsortedMap); return sortedMap; } } class ValueComparator implements Comparator { Map map; public ValueComparator(Map map) { this.map = map; } public int compare(Object keyA, Object keyB) { Comparable valueA = (Comparable) map.get(keyA); Comparable valueB = (Comparable) map.get(keyB); return valueB.compareTo(valueA); } }