StringTokenizer
? String
をchar[]
に変換して、それを繰り返しますか?他に何か?
Forループを使用して文字列を繰り返し、charAt()
を使用して各文字を調べます。 Stringは配列を使って実装されているので、charAt()
メソッドは一定時間操作です。
String s = "...stuff...";
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
//Process char
}
それが私がやることです。それは私にとって最も簡単なようです。
正確さに関する限り、私はそれがここに存在するとは思わない。それはすべてあなたの個人的なスタイルに基づいています。
2つの選択肢
for(int i = 0, n = s.length() ; i < n ; i++) {
char c = s.charAt(i);
}
または
for(char c : s.toCharArray()) {
// process c
}
最初のほうがおそらく速く、次に2番目の方が読みやすいでしょう。
BMP(Unicode Basic Multilingual Plane 以外の文字を扱う場合は、ここで説明している他の手法のほとんどが機能しなくなります。すなわち、 コードポイント がu0000〜uFFFFの範囲外にある場合。これ以外のコードポイントはほとんど死んだ言語に割り当てられているので、これはめったに起こらないでしょう。しかし、これ以外にも便利な文字がいくつかあります。たとえば、数学的表記に使用されるコードポイントや、中国語で固有名をエンコードするために使用されるコードポイントなどがあります。
その場合あなたのコードは次のようになります。
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+を必要とします。
これにはいくつかの専用クラスがあります。
import Java.text.*;
final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
// process c
...
}
クラスパスに Guava がある場合は、次の方法で読みやすくなります。このケースでは、Guavaにはかなり賢明なカスタムList実装さえあるので、これは非効率的ではないはずです。
for(char c : Lists.charactersOf(yourString)) {
// Do whatever you want
}
更新:@Alexが述べたように、Java 8では CharSequence#chars
も使うべきです。型さえIntStreamなので、次のような文字にマッピングすることができます。
yourString.chars()
.mapToObj(c -> Character.valueOf((char) c))
.forEach(c -> System.out.println(c)); // Or whatever you want
String
のコードポイントを反復処理する必要がある場合(これ の回答 を参照)には、 CharSequence#codePoints
メソッドを追加する方法があります。 Java 8では:
for(int c : string.codePoints().toArray()){
...
}
またはforループの代わりに直接ストリームを使用します。
string.codePoints().forEach(c -> ...);
文字のストリームが必要な場合は CharSequence#chars
もあります(ただしIntStream
はないのでCharStream
です)。
Java 8ではそれを次のように解くことができます。
String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
str.codePoints().forEachOrdered(i -> System.out.print((char)i));
メソッドchars()は doc で述べたようにIntStream
を返します。
このシーケンスのchar値をゼロ拡張したintのストリームを返します。サロゲートコードポイントにマップされるすべてのcharは、未解釈のまま渡されます。ストリームの読み取り中にシーケンスが変更された場合、結果は未定義です。
メソッドcodePoints()
はdocに従ってIntStream
も返します。
このシーケンスからコードポイント値のストリームを返します。シーケンス内で見つかったサロゲートペアは、Character.toCodePointによる場合と同様に組み合わされ、結果がストリームに渡されます。通常のBMP文字、対になっていないサロゲート、未定義のコード単位など、その他のコード単位は、int値にゼロ拡張されてからストリームに渡されます。
charとcode pointはどう違うのですか?this articleで述べたように:
Unicode 3.1では補助文字が追加され、合計16文字の
char
で区別できる合計文字数が216文字を超えました。したがって、char
値は、Unicodeの基本的な意味単位への1対1のマッピングを持たなくなりました。 JDK 5は、より大きな文字値のセットをサポートするように更新されました。char
型の定義を変更する代わりに、新しい補助文字のいくつかは2つのchar
値のサロゲートペアによって表されます。命名の混乱を少なくするために、コードポイントを使用して、補足のものも含め、特定のUnicode文字を表す番号を参照します。
最後になぜforEachOrdered
ではなくforEach
ですか?
forEach
の振る舞いは明示的に非決定的です。ここでforEachOrdered
はこのストリームの各要素に対してアクションを実行します。ストリームに定義済みのエンカウンター順序がある場合はストリームのエンカウンター順序で実行されます。そのためforEach
は順序が守られることを保証しません。また、この question もチェックしてください。
文字、コードポイント、グリフ、書記素の違い _については、この question を確認してください。
StringTokenizer
はJDKのレガシークラスの1つなので、使用しません。
Javadocは言います:
StringTokenizer
は互換性の理由から保持されているレガシークラスですが、新しいコードでは使用をお勧めしません。この機能を探している人は誰でも代わりにString
のsplitメソッドかJava.util.regex
パッケージを使うことをお勧めします。
StringTokenizerは、文字列を個々の文字に分割するというタスクにはまったく適していません。 String#split()
では、何にもマッチしない正規表現を使うことで簡単にそれを行うことができます。
String[] theChars = str.split("|");
しかし、StringTokenizerは正規表現を使用していません。また、指定できる区切り文字列が文字間の何にも一致しないということはありません。そこにがあります同じことを達成するために使用できる1つのかわいいハック。そしてそれに区切り文字を返させる:
StringTokenizer st = new StringTokenizer(str, str, true);
しかし、私はそれらを却下する目的のためにこれらのオプションに言及するだけです。どちらの手法も元の文字列をcharプリミティブの代わりに1文字の文字列に分割します。どちらもオブジェクト作成と文字列操作の形で大量のオーバーヘッドを伴います。 forループでcharAt()を呼び出すのと比較すると、事実上オーバーヘッドは発生しません。
パフォーマンスが必要な場合は、あなたがあなたの環境でテストしなければなりません。他に方法はありません。
ここでのコード例:
int tmp = 0;
String s = new String(new byte[64*1024]);
{
long st = System.nanoTime();
for(int i = 0, n = s.length(); i < n; i++) {
tmp += s.charAt(i);
}
st = System.nanoTime() - st;
System.out.println("1 " + st);
}
{
long st = System.nanoTime();
char[] ch = s.toCharArray();
for(int i = 0, n = ch.length; i < n; i++) {
tmp += ch[i];
}
st = System.nanoTime() - st;
System.out.println("2 " + st);
}
{
long st = System.nanoTime();
for(char c : s.toCharArray()) {
tmp += c;
}
st = System.nanoTime() - st;
System.out.println("3 " + st);
}
System.out.println("" + tmp);
オン Javaオンライン
1 10349420
2 526130
3 484200
0
Android x86 API 17では、次のようになります。
1 9122107
2 13486911
3 12700778
0
このサンプルコードはあなたを助けるでしょう!
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);
}
}
this answer および this answer について詳しく説明します。
上記の答えは、コードポイント値で反復しない解決策の多くの問題を指摘しています - 代理文字 では問題があるでしょう。 Javaのドキュメントでは here の問題についても概説しています(「Unicode文字表現」を参照)。とにかく、ここにいくつかの実際のサロゲート文字を補足Unicodeセットから使用し、それらをbackをStringに変換するコードがあります。 .toChars()は文字の配列を返すことに注意してください。もしあなたがサロゲートを扱っているなら、あなたは必然的に2文字を持つでしょう。このコードはany Unicode文字に対して機能するはずです。
String supplementary = "Some Supplementary: ????????????????";
supplementary.codePoints().forEach(cp ->
System.out.print(new String(Character.toChars(cp))));
The Java Tutorials: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
ループを使用してください。