がんばって調べているんですが、わからないので質問します。

HTMLでのメタキャラクタ(「<」「>」「&」「"」など)を
エスケープしたいんですが、うまくいきません。

試した内容は、こんな感じです。

Stringクラスのreplace(char oldChar, char newChar)
を使えば、上手くいくかなと思ったのですが、文字列の
長さが変わってしまう為、使えませんでした。
1文字と1文字の変換だとうまく行くのですが、今回の
場合、1文字を4文字に変換したい為、使えません^^;
< → &lt;

次に考えたのが、文字列のバッファの長さを増やせる
Stringbufferクラスの
replace(int start, int end, String str)
だと、位置を指定しなければならなくて、どうやったら
良いのかわかりません。

みなさん、どのようにしているのでしょうか?
考え方、サンプルなどありましたら、アドバイスお願いします。

A 回答 (3件)

> Stringbufferクラスの


> replace(int start, int end, String str)
> だと、位置を指定しなければならなくて、どうやったら
> 良いのかわかりません。

位置は探してゆけば良いですね。例えば、こんな感じ。

StringBuffer buf = new StringBuffer(対象の文字列);
for (int i = 0 ; i < buf.length() ; ++i) {
 if ( buf.charAt(i) == '<' ) {
  buf.replace(i, i+1, "&lt;");
  i += 3;
 }
}

もっとスマートな解が在りそうな気がするので、自信無しとして置きます (^^;

標準の範囲を超えてしまいますが、参考URLのようなライブラリを使えればメソッド一発ですね。

参考URL:http://www.ingrid.org/jajakarta/regexp/jakarta-r …

この回答への補足

素早いご回答ありがとうございます。

考え方がすごいわかりやすかったです。
そして、さらに質問になりますが、「i+=3」の部分
なんですが、「&lt;」って4文字なんで、「i+=4」
にならないのでしょうか?
微妙に混乱しています^^;

また、色々なメタキャラクタをエスケープするように
作ってみました。現在、「クロスサイトスクリプティング」に
ついて対策を考えているのですが、ひとつわからない事が
あります。

「<」「>」「&」「"」の四つの文字については、
エスケープに成功しました。しかし、「'」(シングル
クォーテーション)だけは、エスケープできません。
画面に「&apos;」と出てしまいます。(IE5.5で確認)
シングルクォーテーションのエスケープの仕方が間違って
いるんでしょうか?
それとも、シングルクォーテーションは、普通エスケープ
しないのでしょうか?
クロスサイトスクリプティングの場合は、シングルクォーテーション
は、エスケープしなくても良いのでしょうか?

かなりたくさん、質問となってしまいますので、ご存知
の部分だけでもわかりましたら、よろしくお願いします。

あと、作成したソースを載せますので、書き方などの
注意もありましたら、よろしくお願いします。

try{
for(int i = 0 ; i < sb.length() ; ++i){
if(sb.charAt(i)=='<'){
sb.replace(i, i+1,"&lt;");
i+=3;
}
if(sb.charAt(i)=='>'){
sb.replace(i, i+1,"&gt;");
i+=3;
}
if(sb.charAt(i)=='&'){
sb.replace(i, i+1,"&amp;");
i+=4;
}
if(sb.charAt(i)=='\''){
sb.replace(i, i+1,"&apos;");
i+=5;
}
if(sb.charAt(i)=='<'){
sb.replace(i, i+1,"&quot;");
i+=5;
}
}
}catch(IndexOutOfBoundsException ioobe){
}

補足日時:2002/03/11 11:59
    • good
    • 0
この回答へのお礼

補足部分で、足りない部分と、間違いがあったので、
お礼に書かせてもらいます。
あわてんぼうで、すいません^^;


String str = "<script>test</script>犬&猫<a href=\"http://www.aaa.com\">AAAA</a>";
StringBuffer sb = new StringBuffer(str);

try{
 for(int i = 0 ; i < sb.length() ; ++i){
  if(sb.charAt(i)=='<'){
   sb.replace(i, i+1,"&lt;");
   i+=3;
  }
  if(sb.charAt(i)=='>'){
   sb.replace(i, i+1,"&gt;");
   i+=3;
  }
  if(sb.charAt(i)=='&'){
   sb.replace(i, i+1,"&amp;");
   i+=4;
  }
  if(sb.charAt(i)=='\''){
   sb.replace(i, i+1,"&apos;");
   i+=5;
  }
  if(sb.charAt(i)=='\"'){
   sb.replace(i, i+1,"&quot;");
   i+=5;
  }
 }
}catch(IndexOutOfBoundsException ex){
}

お礼日時:2002/03/11 12:24

個人的にHTMLタグを変換する機会が多いので、以下のような関数を


持ったクラスを作って利用してます。

単純にif~elseになるべきところを、switchを使っているだけですが。。。

static public String replaceTag(String argOriginalStr) {
 StringBuffer returnStr = new StringBuffer();

 for (int i = 0; i < argOriginalStr.length(); i++) {
  char ch = argOriginalStr.charAt(i);
   switch(ch) {
    case '<':
     returnStr.append("&lt;");
     break;

    case '>':
     returnStr.append("&gt;");
     break;

    default:
     returnStr.append(ch);
     break;
   }
  }
  return new String(returnStr);
 }
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

switchで条件分岐するやり方もありましたね!
ほんと、勉強になります。
if文は、結構使用しますが、switch文は、if文に
比べると使用頻度が少なく思います。
ちょっと忘れ気味でした。

お礼日時:2002/03/12 22:05

> そして、さらに質問になりますが、「i+=3」の部分


> なんですが、「&lt;」って4文字なんで、「i+=4」
> にならないのでしょうか?

for() で +1 されるので、+=3 としています。考え方は4文字だから4増やすで良いです。

> しかし、「'」(シングル
> クォーテーション)だけは、エスケープできません。

「お礼」にあったソースで良いと思いますけどね。シングルクォートもきちんと変換できますよね。

ただ、StringBuffer#replace() で置換した後の i を増やすところでは、";" を指しているので、
if の連続ではなく、if ~ else if と続けた方が良いかも。これでも大丈夫ですけど。
    • good
    • 0
この回答へのお礼

またまた、回答ありがとうございます。

>for() で +1 されるので、+=3 としています。

あっ!なるほどです。
合計4増えるんですね。
一人で考えてたら、+=4にして、失敗する所でした。

if~elseの方がいいかもしれませんね。
if~elseに変えて、使ってみたいと思います。

大変、勉強になりました。
最後まで、付き合って頂いて、感謝しております。
ありがとうございました。

「a-kuma」さんの名前は、「あ~熊さん」なのか、
「ええ熊さん」なのか、すごい気になりますが、
「ええ熊さん」だと思っておきます。
「優しい熊さん」という意味で。

すぐに締め切っても良いのですが、他の方で違った
アドバイスがあるよって人がいるかもしれませんので、
明日締め切らせていただきます。
ご了承ください^^

お礼日時:2002/03/11 18:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

QString(byte[] bytes, int offset, int length)の文字コードは?

String(byte[] bytes, int offset, int length)は、バイト配列(8bitずつのまとまり)を、文字列型に直す、というものだと思うのですが文字コードは何にしたがって直すのでしょうか?

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html

Aベストアンサー

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html#String%28byte[],%20int,%20int%29

>プラットフォームのデフォルト文字セットを使用して、

日本語WindowsならShift_JISでしょう。他の環境では解りません。

#なので僕は

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html#String%28byte[],%20int,%20int,%20java.lang.String%29

で指定するほうが好きです。(コードを読む人に,誤解を与えにくく,異なる環境でも挙動を一致させやすいから移植性も高まると考えるため)

どうしてもデフォルトがほしけりゃ
http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html#defaultCharset%28%29
があるわけですし

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html#String%28byte[],%20int,%20int%29

>プラットフォームのデフォルト文字セットを使用して、

日本語WindowsならShift_JISでしょう。他の環境では解りません。

#なので僕は

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html#String%28byte[],%20int,%20int,%20java.lang.String%29

で指定するほうが好きです。(コードを読む人に,誤解を与えにくく,異なる環境でも挙動を一致させやすいか...続きを読む

QJavaのString、StringBuffer、Charの中でメモリ

JavaのString、StringBuffer、Charの中でメモリの使用が一番良いものは?
Java初心者です。
現在JavaMEのMIDP(2.0)で辞書アプリケーションを作成しています。
携帯電話のメモリが小さいことから不向きではあると思っていますが、できるだけ多くの単語と説明を登録していようとしています。
基本的な文法は通常のJavaと同じだと思います。

大まかな構造は不要部分を省きますと、
-----
class Dictionary extend Canvas(){
 int i,j,start=0,end=0,x=1;
 private static Font fontL=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font.SIZE_LARGE);

 void paint(Graphics g){
  //getsetsumei(x)で単語の意味・説明をString型で受け取っています。
  //substringで一文字ずつ増やしながら文字の横幅をgetWidthで受け取り、
  //描画画面横幅の最大値240を越えないように部分文字列で表示しています。
  //文字の続きは文字サイズの縦幅をfontL.getHeight()で取得し、
  //改行のような形で続けて表示します。
  //また描画画面縦幅の最大領域getHeight()を越えて表示しないために
  //i行目までに描画した文字列の縦幅の総和がこれを越えないようにすることで、
  //無駄な描画をしないようにしています。

  for(i=1;i!=0 && i*fontL.getHeight()<getHeight()-130;i++){//画面縦幅の描画範囲の判定
   while(fontL.stringWidth(getsetsumei(x).substring(start,end+1))<240){//画面横幅の描画範囲の判定
    end++;//横幅に達するまで文字数を増やす
    if(end==getsetsumei(x).length()){//表示すべき文字列の取得が終わった
     g.drawSubstring(getsetsumei(x),start,end-start,0,130+x,Graphics.TOP|Graphics.LEFT);
     i=-1;//終了条件のi!=0を満たさなくするため
     break;
    }
   }
   //描画すべき文字列の一部をSubstringで描画
   g.drawSubstring(getsetsumei(x),start,end-start,0,130+y,Graphics.TOP|Graphics.LEFT);
   start=end;//次の行の描画すべき部分文字列の開始位置を指定
   y+=fontL.getHeight()+1;//改行のためのy座標の移動
  }
 }

 String getsetsumei(int DicNum){
  switch(DicNum){
  case 0:return " ";//説明無し
  case 1:return "辞典,辞書,字引";//Dictionaryの意味、説明
  }
 }
}
-----
となっています。
実際は単語の意味をString型で返すgetsetsumeiの引数xの値を変化させて単語に合わせて意味を取得しようとしています。
改行するプログラムのためにgetsetsumei関数は何度も呼ばれることになるので、できるだけメモリを使用せず、高速にしたいと思っています。
色々調べたところStringは非可変文字列であるとのことでした。
これは説明内容が変更されるたびに別のメモリを確保するということでしょうか?
それとも同じメモリに新しい説明が上書きされるのでしょうか?その場合、StringではなくStringBufferを使用すべき、もしくはchar配列を使用すべきでしょうか?
どなたかご教授願います。

JavaのString、StringBuffer、Charの中でメモリの使用が一番良いものは?
Java初心者です。
現在JavaMEのMIDP(2.0)で辞書アプリケーションを作成しています。
携帯電話のメモリが小さいことから不向きではあると思っていますが、できるだけ多くの単語と説明を登録していようとしています。
基本的な文法は通常のJavaと同じだと思います。

大まかな構造は不要部分を省きますと、
-----
class Dictionary extend Canvas(){
 int i,j,start=0,end=0,x=1;
 private static Font fontL=Font.getFont(Font.FACE_MONOS...続きを読む

Aベストアンサー

「String型のオブジェクトが不変」ということの意味を勘違いされていると思います。オブジェクトの中身とオブジェクトへの参照を区別してください。不変なのはオブジェクトの中身のほう。
下記のようなコードで変数setsumeiはString型オブジェクトへの参照を保持しているだけなので、実行しても変数setsumeiが保存されているメモリが毎回確保されるなどということはなく、同じ場所が上書きされます。

String setsumei;
setsumei=getSetsumei(1);
setsumei=getSetsumei(2);
setsumei=getSetsumei(3);

Qread(buf,int,int)メソッドで1文字取得する

javaを使ってプログラミングを勉強しています。

read(buf,int,int)メソッドで受信したバイトデータをbufに格納していると思うのですが、
格納したバイトの最後の文字を取得する方法が分かりません。

送信側では送信バイトの最後の文字をsにして送信します。
受信側では読み込んだバイトデータの最後の文字がsだったら、
ループを抜けるというようにしたいのです。

どうやって最後の文字を取得するのでしょうか?

Aベストアンサー

read(byte[], int, int)の返値を見れば何バイト読み込めたのかは分かるのですから、その値を使って配列の添字を計算するだけです。

QsetAttribute(String, int)は適用できない

setAttribute(String, int)は適用できない

今、servletでセッションの勉強をしています。
ある本に載っているソースコードをそのままコピーしたんですが、

「HttpSessionのメソッド setAttribute(String, Object)は(String, int)に適用できません。」

…というエラーが出て動きません。
こういう場合、実行するにはどうしたら良いのでしょうか?
アクセスした回数をカウントすることなんてよくあると思うんです。
intも(Stringなんかも)Objectの下に含まれてるんじゃないんですか?
intでも良い気がするんですけど…。
一応、ソースコードを貼っておきます:

### Sample229TestServlet.java ###
package com.tips;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class Sample228TestServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;

private int count = 0;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=Shift_JIS");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
session.setAttribute("param",count++); //問題の箇所
out.println("<html><head><title>Sample228</title></head><body>");
out.println("<h2>SessionAttributeListenerの例</h2>");
out.println("sessionの属性countが" + count + "に変化しました。");
out.println("</body></html>");
out.close();
}
}

### Sample228.java ###
package com.tips;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class Sample228 implements HttpSessionAttributeListener {

public void attributeAdded(HttpSessionBindingEvent event) {
}

public void attributeRemoved(HttpSessionBindingEvent event) {
}

public void attributeReplaced(HttpSessionBindingEvent event) {
ServletContext app = (event.getSession()).getServletContext();
app.log(">> Sample228 Listener detects attribute changed.");
}

}

…必要であれば補足します。では、宜しくお願いします。

setAttribute(String, int)は適用できない

今、servletでセッションの勉強をしています。
ある本に載っているソースコードをそのままコピーしたんですが、

「HttpSessionのメソッド setAttribute(String, Object)は(String, int)に適用できません。」

…というエラーが出て動きません。
こういう場合、実行するにはどうしたら良いのでしょうか?
アクセスした回数をカウントすることなんてよくあると思うんです。
intも(Stringなんかも)Objectの下に含まれてるんじゃないんですか?
intでも良い気がするんですけ...続きを読む

Aベストアンサー

int はプリミティブ型なので、Objectクラスのサブクラスにはあたりません。

> session.setAttribute("param",count++); //問題の箇所
の部分は、ラッパークラスを使用して、
session.setAttribute("param", new Integer(count++));
等としておくと、コンパイルできるんじゃないかな。

QStringBufferからStringへキャストする

StringBufferからStringへキャストする方法としてどちらを用いるのが一般的なのでしょうか
StringBuffer sb
として
public String ***(***)メソッドの最後に

1. return sb.toString()とする
2. return new String(sb)とする

私は1を使っていたのですが、
Javaの規約だか処理能力が良い方法だかに
厳しい人が2を使っていたので少し戸惑う程度ですが…
回答よろしくお願いします。

Aベストアンサー

toString()メソッドは全てのClassのスーパクラスであるObjectクラスのメソッドです。
その他のクラスのtoString()メソッドは、これをオーバライドしたに過ぎません。
toString()メソッドの用途はそのオブジェクトを視覚的にあらわすときに利用します。オブジェクトのダンプイメージです。
今回はStringBufferクラスのtoString()メソッドのためダンプイメージがStringそのもののため問題ありませんが、
「Stringにキャストする」と明示的に処理するには2を使用するのが正解と思います。
格クラスのtoString()メソッドはDEBUGで画面やファイルに出力するときに使用すると考えたほうが賢明と思います。


人気Q&Aランキング

おすすめ情報