5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaでJavaScriptのように正規表現で置換する

Posted at

トリックオアトリート!!
お菓子あげないからいたずらしてください、あらっきぃです。

10月31日に記事を上げるはずがいつの間にか二日も経っていました。何てこった。
ノリが季節外れな感じがしますが気にしないでください。

JavaScriptのString.prototype.replace

JavaとJavaScriptは違います。が、ときとしてJavaでJavaScriptのようなことをしたくなりたくなることがあります。

……というか、JavaScriptのString.prototype.replaceメソッド便利すぎです。forwhileを用いずに全てのマッチに対して処理できるわけですから。こんな風に、

var
str = 'Trick or Treat',

rep = str.replace(/[a-zA-Z]/g, function (c, i, str) {
  console.log("%s:%d:%s", c, i, str);
  return 'a' <= c && c <= 'z' && c.toUpperCase() ||
         'A' <= c && c <= 'Z' && c.toLowerCase();
});

console.log(rep);

実行するとこんな結果になります。

T:0:Trick or Treat
r:1:Trick or Treat
i:2:Trick or Treat
c:3:Trick or Treat
k:4:Trick or Treat
o:6:Trick or Treat
r:7:Trick or Treat
T:9:Trick or Treat
r:10:Trick or Treat
e:11:Trick or Treat
a:12:Trick or Treat
t:13:Trick or Treat
tRICK OR tREAT

めったに使いませんがコールバックの引数として、マッチした文字列マッチしたグループのあとにマッチした位置もとの文字列が入ってきます。

便利ですよね~。

Javaって…

これと同じことをJavaでやるとですね…

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

public class RegexSample {

    static public void main(String... args) {
        String str = "Trick or Treat";
        Pattern pat = Pattern.compile("[a-zA-Z]");
        Matcher m = pat.matcher(str);

        StringBuilder sb = new StringBuilder();
        int start = 0;
        while(m.find()) {
            System.out.printf("%s:%d:%s\n", m.group(), m.start(), str);
            sb.append(str.substring(start, m.start()));
            start = m.end();
            char c = m.group().charAt(0);
            if ('a' <= c && c <= 'z') sb.append((char)(c - 0x20));
            else if ('A' <= c && c <= 'Z') sb.append((char)(c + 0x20));
        }
        sb.append(str.substring(start));

        System.out.println(sb.toString());
    }

}

こんな感じでしょうか? そもそも正規表現を使うのがナンセンスな気がします。

ちょっとwrapしてみる

なのでこんなクラスを用意してみました。

Replacer.java
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Replacer {

    static String replace(String str, Pattern pat, ReplaceCallback callback) {
        StringBuilder sb = new StringBuilder();

        Matcher m = pat.matcher(str);
        int start = 0;
        while (m.find()) {
            sb.append(str.substring(start, m.start()));
            String matched = str.substring(m.start(), m.end());
            start = m.end();
            ArrayList<String> groups = new ArrayList<>();
            for (int j = 0; j <= m.groupCount(); j++) {
                groups.add(m.group(j));
            }
            sb.append(callback.replaceString(matched, groups, str, pat, m.toMatchResult()));
        }
        sb.append(str.substring(start));

        return sb.toString();
    }

}
ReplaceCallback.java
import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;

public interface ReplaceCallback {
    String replaceString(String matched, List<String> groups, String str, Pattern pat, MatchResult matchResult);
}

これを使うと、さっきのコードをこんな風に書きなおすことができます。

RegexExample.java
import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;

public class RegexSample {

    static public void main(String... args) {
        String str = "Trick or Treat";
        Pattern pat = Pattern.compile("[a-zA-Z]");
        String rep = Replacer.replace(str, pat, new ReplaceCallback() {
            @Override
            public String replaceString(String matched, List<String> groups,
                    String str, Pattern pat, MatchResult matchResult) {
                System.out.printf("%s:%d:%s\n", matched, matchResult.start(), str);
                char c = matched.charAt(0);
                c = (char)('a' <= c && c <= 'z' ? c - 0x20 :
                           'A' <= c && c <= 'Z' ? c + 0x20 : c);
                return Character.toString(c);
            }
        });

        System.out.println(rep);
    }
}

どうでしょうか? さっきよりもJavaScriptのコードに近づいて、読みやすくなった気がします。

今回載せたコードは全てパブリックドメインとして煮るなり焼くなり好きにしてやってください。

TODO

JavaDocを書く。

5
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?