C言語は、文字列型の基本型が存在しません。文字列は、charの1byteを指し示すポインタで管理しました。
((char*)型のポインタで管理していました。)
C言語の文字列管理参考⇒(確認後はブラウザの戻る操作で戻ってください)
byte単位で表現できる場合は扱いやすいのですが、2byte文字を含む場合に扱い難くなります。
例えば日本語の文字は2byte使うShift JIS系の文字列を扱えるコンパイラにおいて、
char *s="あいうabc"と宣言した時、
sが指し示す位置から始まるbyte列は次のようになります。
あ | い | う | a | b | c | ||||
---|---|---|---|---|---|---|---|---|---|
'0x082' | '0x0A0' | '0x082' | '0x0A2' | '0x082' | '0x0A4' | '0x61' | '0x62' | '0x63' | '0x0' |
ここで、2文字目のいを出力する際、
putchar(a[1]);としても'0x0A0'の出力で文字化けになるでしょう。
正しくいを表示させるには、
putchar(a[2]);とputchar(a[3]);の連続2byte出力させる実行が必要です。
しかも、文字列管理方法は処理系依存なので、OSによって異なるbyte列になり、扱い難いのです。
文字列型のStringクラスや文字のchar型がが存在します。
(char型は基本型ですが、文字列のString型は基本型ではありません。参照型です。)
そして文字の内部コードはUnicodeの2byteを使うことに決まっているので、比較的簡単に取り扱えます。
例えば、
String s = "あいうabc";と変数sが用意されるとき、先頭を0、1と数えた1番目の
いの文字を出力するには、次のようにcharAtメソッドで指定の位置にある文字(char型)を
取り出せます。
char c = s.charAt(1);
System.out.print(c);
また文字列定数がStringクラスのオブジェクトなので、その機能のcharAtメソッドが使ます。
よって、以下で同じように い が出力できます。
System.out.print( "あいうabc".charAt(1) );
そしてJavaでは、+演算子で文字列の連結ができます。
例えば、次のコードの出力結果で、 a+b+c=12 が得られます。
int v1 = 3; int v2 = 5; int v3 = 4; System.out.print("a+b+c=" + (v1 + v2 + v3));
これは+の演算子の機能で、一方のオペランドがStringであるとき他方をStringに変換して連結した文字列
を演算子の結果にするからです。つまり、(v1 + v2 + v3)の演算結果の12が連結されたわけです。
これを、System.out.print("a+b+c=" + v1 + v2 + v3)としてしまうと、
a+b+c=354の結果になってしまいます。
これは+演算は左結合なので、始めに左の"a+b+c=" + v1が演算されて、"a+b+c=3"の
演算結果の文字列が得られ、それが次の+演算のオペランドになっていくからです。
なお、改行("\n")を伴う表示は、printlnを使います。(print lineの意味です。)つまり以下の2行で、同じ出力が得られます。
System.out.print("a+b+c=" + (v1 + v2 + v3) + "\n");
System.out.println("a+b+c=" + (v1 + v2 + v3));
よく使われる文字列操作は、連結、文字数取得、文字列の検索、部分文字列の抽出、等価チェック、大小の比較、数値変換などが挙げられます。
C言語の文字列管理参考⇒(確認後はブラウザの戻る操作で戻ってください)
JavaのString型は、参照型で if( str == "abc")〜で str の参照内容が"abc"と等しいか判定ができません。
参照型はC言語のポインタと同じように、
データの中身をチェックするのではなく、『同じ記憶域を指し示すか?』 の判定だからです。
Javaでは、equalsメソッドを使って if( str.equals("abc") == true)〜と書きます
Javaでは次のようなメソッドがよく使われます。なお、strは、文字列オブジェクトで表記する意味です。
操作 | メソッドや操作 | 例 |
---|---|---|
連結 |
+演算子 |
String s = str + "\r\n"; |
文字数取得 |
str.length() |
String s = "あいうabc"; |
指定位置の文字取得 |
str.charAt(添え字) |
String s = "あいうabc"; |
文字列の検索 |
str.indexOf(検索文字列) |
String s = "あabc45bce"; |
str.indexOf(検索文字列, |
String s = "あabc45bce"; |
|
str.lastIndexOf(検索文字列, |
String s = "あabc45bce"; |
|
部分文字列 |
str.substring(先頭位置) |
String s = "あabc45bce"; |
str.substring(先頭位置, |
String s = "あabc45bce"; |
|
str.trim() |
String s = " abc "; |
|
等価チェック |
str.equals(文字列) |
String s = "あab"; |
str.startsWith(文字列) |
String s = "あabc45bce"; |
|
str.endsWith(文字列) |
String s = "あabc45bce"; |
|
大小の比較 |
str.compareTo(文字列) |
String s = "あab"; |
str.compareToIgnoreCase(文字列) |
String s = "あa5"; |
|
数値へ変換 |
Integer.parseInt(10進文字列) |
int data = Integer.parseInt("5432"); |
Integer.parseInt(文字列 , 基数) |
int data = Integer.parseInt("FF" , 16); |
|
Double.parseDouble(文字列) |
double data = Double.parseDouble("12.3145"); |
|
数値から |
Integer.toString(数値,基数) |
String data = Integer.toString(18,2); |
数値への変換
では、各基本型に対応するクラスが用意されているので、それらのクラスを使います。
int型ではIntegerクラス、double型ではDoubleクラスです。
この変換において、実行エラーが起きる場合があります。
次のコードでは、コンパイルエラーはありませんが、実行時にエラーが発生します。以下のその例も示します。
public class Test { public static void main(String[] arg) { double data = Double.parseDouble("12.314X"); // 数字でないXの文字を含む(これがエラー要因) System.out.println(data); } }
Exception in thread "main" java.lang.NumberFormatException: For input string: "12.314X" at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224) at java.lang.Double.parseDouble(Double.java:510) at Test.main(Test.java:7)
上記実行エラーで、NumberFormatExceptionの部分が、発生した例外クラスの名前で、
この名前からエラーの理由を推測します。(数を表現する書式エラーとなります)
またこのエラーの発生箇所が、FloatingDecimal.javaの1224行目です。
このFloatingDecimal.javaは、JDKの開発用ディレクトリ内に存在するJava APIのソースです。
(Java開発キットの中には、全てのクラスのソースが存在し、圧縮されたsrc.zip内にあります。)
エラー発生はここですが、その箇所を呼び出す命令が、Double.javaの510行目で、
それを呼び出す命令が、Test.javaの7行目と分かります。
このようにして、エラーの発生源から問題点を推測して直していきます。
次のプログラムで、文字列内の個々の文字を取り出して、コードを確認する。 これで、Javaの文字が16ビットのユニコードで管理されていることが確認できる。
str="12AB あい"; for(int i=0; i < str.length(); i++){ int c = (int)str.charAt(i); System.out.print(Integer.toString(c, 16) + " "); }
31 32 41 42 20 3042 3044
この文字列を外部(例えばファイル)で使うような場合、各種文字セットが存在します。
例えば UTF-8の文字セットのバイナリ列が必要な場合は、次のように配列に変換してます。
その確認例を示します。
str="12AB あい"; byte []a = str.getBytes("utf-8"); for(int i=0; i < a.length; i++){ System.out.print(Integer.toString(a[i] & 0x0ff, 16) + " "); }
31 32 41 42 20 e3 81 82 e3 81 84
windows-31jの文字セットのバイナリ列の確認例を示します。
str="12AB あい"; byte []a = str.getBytes("windows-31j"); for(int i=0; i < a.length; i++){ System.out.print(Integer.toString(a[i] & 0x0ff, 16) + " "); }
31 32 41 42 20 82 a0 82 a2