質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Java

    16160questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • アルゴリズム

    512questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

文字列中で、AをBに、BをAに置換したい。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,182

nuiri1343

score 46

質問

表題の通り、任意の文字列中の、アルファベットAをBに、BをAに置換したいです。
Stringクラスの、replaceAllメソッドを使えば、AをBに置換することはできますが、
その後もう一度replaceAllメソッドで、BをAに置換しようとすると、先ほどAをBに置換したところまでAになってしまいます。
どうしたらいいのでしょうか?

たとえば、文字列中に数字が含まれないことが証明されているようでしたら、
Aを1に置換、Bを0に置換し、1をBに置換、0をAに置換すれば目的の動作は達成できると思い、
そのソースコードを作りましたが、
もしこの文字列に何のきまりもなく、数字も小文字アルファベットも記号も含まれるとしたら...
アドバイスお願いいたします。

書いてみたソースコード

public class Main{
 public static void main(String[] args){
  String s = new java.util.Scanner(System.in).nextLine();
  s = s.replaceAll("A","1");
  s = s.replaceAll("B","0");
  s = s.replaceAll("1","B");
  s = s.replaceAll("0","A");
  System.out.println(s);
 }
}

補足

実際にコードを書くのは自分で頑張りますので、ヒントだけでも教えていただけると幸いです。

追記

正規表現を使ったプログラムを書いてみたのですが
もっと効率よくならないか、悩んでいます。見ていただけませんでしょうか?
今回は、"abc"と"cba"の変換なので、どちらも3文字ですが、文字数が違う場合も想定して書いてみました。

import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Main{
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    String s = sc.nextLine(); //置換したい文字列を受け取る

    //abcをcbaに、cbaをabcに置換する。

    Pattern p1 = Pattern.compile("abc|cba");
    Matcher m;

    int next = 0; //分割点
    String result = "";

    while(true){
        m = p1.matcher(s);
        if(m.find()){
        next = m.start();
        result += s.substring(0,next); //マッチした手前までをresultへ入れる
        s = s.substring(next); //resultに入れた分を削除

        if(s.substring(0,3).equals("abc")){ //マッチしたのが"abc"だったら
            result+="cba"; //resultに"cba"を入れる
            if(s.length()==3){ //マッチした部分が文の最後だったら
            break;
            }
            s = s.substring(3); //残りの部分をsに入れる
        }else{
            result+="abc";
            if(s.length()==3){
            break;
            }
            s = s.substring(3);
        }

        }else{
        result += s;
        break;
        }
    }
    System.out.println(result);
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+4

replaceAllを使うことに固執せず、一文字ずつチェックして文字列を組み直してみてはいかがでしょう。

追記に助言

  • 何度も文字列を連結するなら、Stringに対する+演算子を使うより、StringBuilderを使ったほうが良い
  • ループのたびにMatcherを作成しなおしているのが無駄。前回マッチ時の終端位置を取得し、同じMatcherを使いまわせるようにするべき
  • 「何とマッチしたか」はgroupメソッドで取得できる。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/13 14:01

    なるほど!

    もし、AやBが人文字ではなくこれもまた文字列だった場合、
    たとえば、ABC→CBAとCBA→ABCだった場合は、
    とても長く面倒なものになると思うのですが

    その場合も、一文字ずつチェックして、一致する部分を探してとやらねばならないのでしょうか?

    キャンセル

  • 2017/05/13 14:08

    その場合、正規表現による検索と併用するといいでしょう。

    キャンセル

  • 2017/05/13 14:18

    なるほど。
    頑張ってコード書いてみます!

    キャンセル

  • 2017/05/13 14:39

    もしくは、indexOf(String, int)を繰り返し利用するという方法も考えられます。

    キャンセル

+2

質問のコードを HashMap を使って汎用的に書き直してみました。

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.regex.*;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        System.out.println(swapString("abcdefghi", "abc", "ghi"));
    }

    static String swapString(String source, String a, String b)
    {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put(a, b);
        map.put(b, a);
        Pattern pattern = Pattern.compile(Pattern.quote(a) + "|" + Pattern.quote(b));
        Matcher matcher = pattern.matcher(source);
        StringBuffer sb = new StringBuffer();
        while (matcher.find())
        {
            matcher.appendReplacement(sb, map.get(matcher.group()));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
}

出力

ghidefabc

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

Java勉強中なのであってるかどうか?・・・なのですが
文字列をコピーして、各々A,B置き換えてマージするのはどうでしょう?
・Aを置き換えた文字列とBを置き換えた文字列を作る
・charAt(n)で比較
・違ったらsetCharAt(n)で置き換え

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/15 15:01

    なるほど。
    そんな考え方があったんですね!

    試しにプログラムを作ってみたのですが、
    今回のように置換する文字列の文字数が等しい場合はうまくいくのですが、
    もし文字数が違った場合、難しいのではないでしょうか?


    import java.util.Scanner;

    public class Main{
    public static void main(String[] args){
    Scanner sc = new Scanner(System.in);
    String s = sc.nextLine();


    String a = s.replace("abc","cba");
    String b = s.replace("cba","abc");

    String result = "";
    for(int i=0;i<a.length();i++){
    if(a.charAt(i)==b.charAt(i)){
    result += a.charAt(i);
    }else{
    if(a.charAt(i)==s.charAt(i)){
    result += b.charAt(i);
    }else{
    result += a.charAt(i);
    }
    }
    }
    System.out.println(result);
    }
    }

    キャンセル

  • 2017/05/15 16:14

    文字数が違うなら文字列を逆順に(末尾から先頭に向かって)置換するといいよ。

    キャンセル

-2

AをCに置換
BをAに置換
CをBに置換
とか?

Cは既存文字列と被らないようなものにすればいい。
例えば、$abcsefghijklmn...$ とかね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/20 18:19

    絶対に既存文字列と被らないと言い切れないので難しいですよね

    キャンセル

  • 2017/05/20 18:24

    それ質問の時点でやってて、一般の文字列だと出来ないからどうしたら良いかって質問ですよ?

    キャンセル

  • 2017/05/20 20:53

    最初のA->B,B->Aじゃなくて数字の方を言ってます?そりゃ無理でしょ。
    自分が言ってるのは仲介するCで、被らない文字列を入れる方法ですね。
    上記固定の文字列だと問題あるようであれば、一度テキストを検索して当てはまるようであれば、機械的に再定義する仕組みにすればいいし。

    キャンセル

  • 2017/05/23 00:25

    質問文に書いてある数字ってのはただの例えで、
    何か違う文字列や文字、記号などを仲介する方法は最初に思いつきましたが、
    動作の保証ができないという状態でした。
    確かに、文字列を検索して当てはまらない言葉を使えば実現はできますが、、
    無駄に長くなってしまいますし、スマートでないなと思いますし、
    置き換え後、置き換えた場所の前後との文字列の組み合わせで、予想外の動作が起きてしまう可能性など否定できないため
    あらゆる状態に対処できるようにという考え方から行きますと
    他の方法を探したいなというのが本音です。

    キャンセル

  • 2017/05/23 07:22

    仲介する方法では、ASCIIコード表の空白未満の制御コードを使うという手もあるかなと思います。対象の文字列次第ですが。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Java

    16160questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • アルゴリズム

    512questions

    アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。