Sat, November 10, 2007
やや複雑な文字列の置き換え java.util.regex
HTMLやXML文書中の特定エレメントだけを対象にして、 文字列置き換え処理をしなければいけない、 という仕事に直面しているのだが、 正規表現を使った置き換えプログラムを何度も書くことになったので、ここに記録。
firefexのfexだけをfoxに直したい...という例
ここでは、実際のXMLの事例ではなく、 ごく単純な例で説明。
fox,fex,firefox,firefex,
firefoxという文字列のfox部分をfexと間違えて綴っているところがある。 これだけを直したい、という話。
単純に java.lang.StringのreplaceAll("fex","fox")のような置き換え処理を すると、はじめに出現している fex も fox に置き換えてしまうので、 不都合...ということにします。
import java.io.*;
import java.util.regex.*;
import org.apache.commons.io.IOUtils;
public class Test{
static String toString(File f) throws Exception{
String text=null;
InputStream fin=new FileInputStream(f);
text=IOUtils.toString(fin,"UTF-8");
fin.close();
return text;
}
static String replace(String text){
Pattern pat=Pattern.compile("(fire)fex");
StringBuffer sb=new StringBuffer();
Matcher m=pat.matcher(text);
while( m.find() ){
String g1=m.group(1);
m.appendReplacement(sb, g1+"fox");
}
m.appendTail(sb);
return sb.toString();
}
public static void main(String[] args){
try{
File f=new File("firefox.txt");
String text=toString(f);
System.out.print("src :"+text);
String result=replace(text);
System.out.print("result:"+result);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
結果
src :fox,fex,firefox,firefex,
result:fox,fex,firefox,firefox,
RE(jakarta-regexp)を使った場合
java.util.regexではなくて、 jakarta-regexp を使って同じことをする場合...
import java.io.*;
import org.apache.commons.io.IOUtils;
import org.apache.regexp.CharacterIterator;
import org.apache.regexp.RE;
import org.apache.regexp.ReaderCharacterIterator;
public class Test2{
static String toString(File f) throws Exception{
String text=null;
InputStream fin=new FileInputStream(f);
text=IOUtils.toString(fin,"UTF-8");
fin.close();
return text;
}
static String replace(String text){
RE pat=new RE("(fire)fex");
StringBuffer sb=new StringBuffer();
StringReader sr=new StringReader(text);
CharacterIterator in=new ReaderCharacterIterator(sr);
int pointer=0;
while(pat.match(in,pointer)){
int start=pat.getParenStart(0);
String part=in.substring(pointer,start);
sb.append(part);
String g1=text.substring(pat.getParenStart(1),pat.getParenEnd(1));
sb.append(g1+"fox");
pointer=pat.getParenEnd(0);
}
String tail=in.substring(pointer);
sb.append( tail );
sr.close();
return sb.toString();
}
public static void main(String[] args){
try{
File f=new File(args[0]);
String text=toString(f);
System.out.print("src :"+text);
String result=replace(text);
System.out.print("result:"+result);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
java.util.regexの方がちょっとわかりやすい気がします。 また置き換え対象とするテキストのサイズが大きい場合は、 JavaVMのメモリヒープを大きくとっておかないと、Out of Memory エラーが出ます。 (java.util.regexパッケージでも同じかもしれませんが、そちらではテストしていません。)