プログラマメモ2 - programmer no memo2

文字コードのための手習いその2 2010/11/11

Javaです。文字コードのための手習いその2です。

まずこちらにある対応表をベースに実験です。



package a;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

public class A {

/**
* バイトの配列を16進数表現で標準出力します。
*
* @param bs
*/
static void printHex(byte[] bs) {
for (byte b : bs) {
int i = (int) b;
String s = String.format("%h", 0x00000000ff & i).toUpperCase();
System.out.print((s.length() < 2 ? "0" : "") + s + " ");
}
System.out.println();
}

/**
* intをバイト配列にします。
*
* @param a
* @return
*/
static byte[] toBytes(int a) {
byte[] bs = new byte[4];
bs[3] = (byte) (0x000000ff & (a));
bs[2] = (byte) (0x000000ff & (a >> 8));
bs[1] = (byte) (0x000000ff & (a >> 16));
bs[0] = (byte) (0x000000ff & (a >> 24));
return bs;
}

/**
* バイトの配列をintにします。
*
* @param bs
* @return
*/
static int toInt(byte[] bs) {
return ByteBuffer.wrap(bs).asIntBuffer().get();
}

/**
* バイトの配列を結合していきます。
*
* @param top
* @param bs
* @param bottom
* @return
*/
static byte[] sandwich(byte[] top, byte[] bs, byte[] bottom) {
byte[] ret = new byte[top.length + bs.length + bottom.length];
int[] pos = { 0, top.length, top.length + bs.length };
System.arraycopy(top, 0, ret, pos[0], top.length);
System.arraycopy(bs, 0, ret, pos[1], bs.length);
System.arraycopy(bottom, 0, ret, pos[2], bottom.length);
return ret;
}

public static void main(String[] args) throws UnsupportedEncodingException {
a();
}

static void print(int i, String characterset)
throws UnsupportedEncodingException {
byte[] bs = toBytes(i);
print(bs, characterset);
}

static void print(byte[] bs, String characterset)
throws UnsupportedEncodingException {
String s = new String(bs, characterset);
System.out.println(characterset + ":" + s);
}

static void a() throws UnsupportedEncodingException {
{
System.out.println("♂♀");

// Shift_JIS-2004 (JIS X 0213:2004 Appendix 1) vs Unicode mapping
// tableより
// 0x8189 U+2642 # MALE SIGN
// 0x818A U+2640 # FEMALE SIGN
print(0x8189, "sjis");
print(0x818A, "sjis");

// EUC-JIS-2004 (JIS X 0213:2004 Appendix 3) vs Unicode mapping
// tableより
// 0xA1E9 U+2642 # MALE SIGN
// 0xA1EA U+2640 # FEMALE SIGN
print(0xA1E9, "EUC_JP_LINUX");
print(0xA1EA, "EUC_JP_LINUX");

// ISO-2022-JP-2004 vs Unicode mapping tableより
// 3-2169 U+2642 # MALE SIGN
// 3-216A U+2640 # FEMALE SIGN
print(sandwich(new byte[] { 0x1B, 0x24, 0x42 }, new byte[] { 0x21,
0x69 }, new byte[] { 0x1B, 0x28, 0x42 }), "ISO2022JP");
print(sandwich(new byte[] { 0x1B, 0x24, 0x42 }, new byte[] { 0x21,
0x6A }, new byte[] { 0x1B, 0x28, 0x42 }), "ISO2022JP");

// 最後にunicode
print(0x2642, "utf16");
print(0x2640, "utf16");

// String s = "♂";
// byte[] bs = s.getBytes("ISO2022JP");
// printHex(bs);
// System.out.println(new String(bs, "ISO2022JP"));
}

}

}


結果

♂♀
sjis:♂
sjis:♀
EUC_JP_LINUX:♂
EUC_JP_LINUX:♀
ISO2022JP:♂
ISO2022JP:♀
utf16:♂
utf16:♀

文字コードのための手習いその1 2010/09/21

Javaです。
現行とか次期とかいう用語がでてくるプロジェクトにはかならずといっていいほどでてきて頭を悩ますのがおそらく文字コードだろうと思われます。

ちょっといろいろ理解不足なので、プログラム書いて納得していこうかと思います。

import java.io.UnsupportedEncodingException;

public class TestJis {

public static void main(String[] args) throws UnsupportedEncodingException {
a();
b();
}

static void a() throws UnsupportedEncodingException {
String s = "日本語";
byte[] sjis = s.getBytes("sjis");
byte[] jis = new String(sjis, "sjis").getBytes("jis");
String s_jis = new String(jis, "jis");
System.out.println(s_jis);
for (byte b : sjis) {
System.out.print(Integer.toHexString((int) b) + " ");
}
System.out.println();
int cnt = 0;
for (byte b : jis) {
System.out.print(Integer.toHexString((int) b) + " ");
cnt++;
}
System.out.println();
System.out.println("==>" + cnt);
}

static void b() throws UnsupportedEncodingException{

// 46 7c 4b 5c 38 6c
byte[] top = {0x1b, 0x24, 0x42};
byte[] bottom = {0x1b, 0x28, 0x42};

byte[] bs = {0x46, 0x7c, 0x4b, 0x5c, 0x38, 0x6c};
byte[] jis = sandwich(top, bs, bottom);
System.out.println(new String(jis, "jis"));
for (byte b : jis) {
System.out.print(Integer.toHexString((int) b) + " ");
}
}

/**
* バイトの配列を結合していきます。
*
* @param top
* @param bs
* @param bottom
* @return
*/
static byte[] sandwich(byte[] top, byte[] bs, byte[] bottom) {
byte[] ret = new byte[top.length + bs.length + bottom.length];
int[] pos = {0, top.length, top.length + bs.length};
System.arraycopy(top, 0, ret, pos[0], top.length);
System.arraycopy(bs, 0, ret, pos[1], bs.length);
System.arraycopy(bottom, 0, ret, pos[2], bottom.length);
return ret;
}

}



実行結果はこんな感じででてきますよ。
日本語
ffffff93 fffffffa ffffff96 7b ffffff8c ffffffea
1b 24 42 46 7c 4b 5c 38 6c 1b 28 42
==>12
日本語
1b 24 42 46 7c 4b 5c 38 6c 1b 28 42

コードアシストしてくれるアプリケーションを作るための手習い その2- eclipse,JFace,swt 2008/09/06

前回に続いて実験。

(1)
eclipseでコード書いているとctrl + spaceでコードアシストしてくれるので、ためしみました。
キーストロークで"Ctrl+Space"するとよいようです。

(2)
入力された値によって提案するもんもんを変更したい場合。
org.eclipse.jface.fieldassist.IContentProposalProviderを工夫すればよい感じ。
もっといいコードの書き方があるかも。
これが実現できると、入力している語の続きの文字を提案できるから入力を軽減できますね。

実行はこんな感じです。



コードです。

import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;

/**
* コードアシストの手習い
*
* @author nakawakashigeto
*
*/
public class Main extends ApplicationWindow {
public Main() {
super(null);
}

public static void main(String[] args) {

Main window = new Main();
window.setBlockOnOpen(true);
window.open();
Display.getCurrent().dispose();
}

protected Control createContents(Composite parent) {

Text text = new Text(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
IControlContentAdapter contentAdapter = new TextContentAdapter();

/*
* 提案する内容提供します。
*/
IContentProposalProvider provider = new IContentProposalProvider() {

public IContentProposal[] getProposals(String content, int pos) {

return createProposals(content, pos);
}

};

/*
* ctrl + spaceでコードアシストするようにしています。
*/
ContentProposalAdapter contentProposalAdapter = new ContentProposalAdapter(
text, contentAdapter, provider, keystroke("Ctrl+Space"), null);

return parent;
}

/**
* <p>
* 入力された文字列が「あなたは」で終わっている場合に提案します。
* </p>
*
* @param content
* @param pos
* @return
*/
static public IContentProposal[] createProposals(final String content,
final int pos) {

if (content.length() == 0 || !(0 < (pos - 3))
|| "あなたは".equals(content.substring(pos - 3, pos))) {
return new IContentProposal[] {};
}

String[] strings = { "愉快な人","ちょっとあぶない", "いい人", "いやな人", "楽しい人"};

IContentProposal[] proposals = new IContentProposal[strings.length];
for (int i = 0; i < proposals.length; i++) {
final String s = strings[i];
proposals[i] = new IContentProposal() {
public String getContent() {
return "、ずばり" + s;
}

public int getCursorPosition() {
return 0;
}

public String getDescription() {
return "あなたは" + s;
}

public String getLabel() {
return s;
}
};

}

return proposals;
}

static KeyStroke keystroke(String s) {
try {
return KeyStroke.getInstance(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}

}

手習い しゅうごうのえんざん 2008/02/28
2008/02/28

Groovyです。

集合の計算


def a = [1, 2, 4]
def b = [1, 2, 3, 4]
def c = [3, 4]
def d = [1, 4]

// a ∩ (b ∪ c ∪ d)
// b ∩ (c ∪ d)
// c ∩ d

a = a - (b + c + d)
b = b - (c + d)
c = c - d
println a
println b
println c
println d


結果
[]
[2]
[3]
[1, 4]

javassistを使って、既存のクラスのメソッドを置き換えるための手習い。 2008/02/20

狙いはjaspereportsのnet.sf.jasperreports.engine.export.renderParagraphの処理を変更したいということ。

対象としているのは、2.0.4
使用しているjavassistのバージョンは、3.6.0.GA

手順
(1)
まず、renderParagraphメソッドから中身をごっそりファイルにしておく。
(2)
1.でとったテキストを修正する、クラスはパッケージまでつけて、メソッドの引数は$1,$2,$3...としておく。
あと、きちんと確認がとれてないのですが、どうもcaseに他のクラスの定数をかくとどうもだめっぽい。これはあとで確認します※
(3)
javassistを使ってsetBodyして、toClassして凍らせる。このときにエラーがでないことをめざす。

(1)

{
AttributedCharacterIterator paragraph = null;

if (lastParagraphText == null)
{
paragraph =
new AttributedString(
" ",
new AttributedString(
allParagraphs,
lastParagraphStart,
lastParagraphStart + 1
).getIterator().getAttributes()
).getIterator();
}
else
{
paragraph =
new AttributedString(
allParagraphs,
lastParagraphStart,
lastParagraphStart + lastParagraphText.length()
).getIterator();
}

LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, LINE_BREAK_FONT_RENDER_CONTEXT);//grx.getFontRenderContext()

while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached)
{
//eugene fix - start
int startIndex = lineMeasurer.getPosition();
//eugene fix - end

TextLayout layout = lineMeasurer.nextLayout(formatWidth);

if (isMinimizePrinterJobSize)
{
//eugene fix - start
AttributedString tmpText =
new AttributedString(
paragraph,
startIndex,
startIndex + layout.getCharacterCount()
);
layout = new TextLayout(tmpText.getIterator(), grx.getFontRenderContext());
//eugene fix - end
}

float lineHeight = lineSpacingFactor *
maxFontSizeFinder.findMaxFontSize(
new AttributedString(
paragraph,
startIndex,
startIndex + layout.getCharacterCount()
).getIterator(),
fontSize
);

if (drawPosY + lineHeight <= textHeight)
{
drawPosY += lineHeight;

switch (horizontalAlignment)
{
case JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED :
{
if (layout.isLeftToRight())
{
drawPosX = 0;
}
else
{
drawPosX = formatWidth - layout.getAdvance();
}
if (lineMeasurer.getPosition() < paragraph.getEndIndex())
{
layout = layout.getJustifiedLayout(formatWidth);
}

break;
}
case JRAlignment.HORIZONTAL_ALIGN_RIGHT :
{
drawPosX = formatWidth - layout.getAdvance();
break;
}
case JRAlignment.HORIZONTAL_ALIGN_CENTER :
{
drawPosX = (formatWidth - layout.getAdvance()) / 2;
break;
}
case JRAlignment.HORIZONTAL_ALIGN_LEFT :;
default :
{
drawPosX = 0;
}
}

draw(layout);
}
else
{
isMaxHeightReached = true;
}
}
}


(2)加工するためのコード
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class FileA {
public static void main(String[] args) throws IOException {

InputStream stream = FileA.class.getResourceAsStream("a.txt");
BufferedReader reader = new BufferedReader(
new InputStreamReader(stream));
String s = null;
while ((s = reader.readLine()) != null) {
String ss = s.replaceFirst("//.*$", "");
ss = ss.replaceAll("\"", "\\\\\"");

ss = ss.replaceAll("JRAlignment\\.HORIZONTAL_ALIGN_LEFT", "1");
ss = ss.replaceAll("JRAlignment\\.HORIZONTAL_ALIGN_CENTER", "2");
ss = ss.replaceAll("JRAlignment\\.HORIZONTAL_ALIGN_RIGHT", "3");
ss = ss.replaceAll("JRAlignment\\.HORIZONTAL_ALIGN_JUSTIFIED", "4");

ss = ss.replaceAll("JRAlignment", "net.sf.jasperreports.engine.JRAlignment");
ss = ss.replaceAll("LineBreakMeasurer", " java.awt.font.LineBreakMeasurer");
ss = ss.replaceAll("TextLayout", "java.awt.font.TextLayout");
ss = ss.replaceAll("AttributedCharacterIterator", " java.text.AttributedCharacterIterator");
ss = ss.replaceAll("AttributedString", "java.text.AttributedString");
ss = ss.replaceAll("JRAlignment", "net.sf.jasperreports.engine.JRAlignment");

ss = ss.replaceAll("allParagraphs", "\\$1");
ss = ss.replaceAll("lastParagraphStart", "\\$2");
ss = ss.replaceAll("lastParagraphText", "\\$3");
ss = ss.replaceAll("LINE_BREAK_FONT_RENDER_CONTEXT", "net.sf.jasperreports.engine.export.TextRenderer.LINE_BREAK_FONT_RENDER_CONTEXT");

// java.awt.Graphics2D;
// java.awt.font.FontRenderContext;
// java.awt.font.LineBreakMeasurer;
// java.awt.font.TextLayout;
// java.text.AttributedCharacterIterator;
// java.text.AttributedString;
// java.util.StringTokenizer;
//
// net.sf.jasperreports.engine.JRAlignment;
// net.sf.jasperreports.engine.util.JRProperties;
// net.sf.jasperreports.engine.util.JRStyledText;
// net.sf.jasperreports.engine.util.MaxFontSizeFinder;

System.out.printf("buffer.append(\"%s\");%n", ss);
}

}

}


(3)javassistを使ってメソッドの処理を変更。
import net.sf.jasperreports.engine.export.TextRenderer;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public class TestJavassist {

public static void main(String[] args) throws NotFoundException,
CannotCompileException {
a();
TextRenderer textRenderer = new TextRenderer(false);
}

static void a() throws NotFoundException, CannotCompileException {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("net.sf.jasperreports.engine.export.TextRenderer");
CtMethod method = cc.getDeclaredMethod("renderParagraph");
StringBuffer buffer = new StringBuffer();
buffer.append(" {");
buffer.append(" java.text.AttributedCharacterIterator paragraph = null;");
buffer.append(" ");
buffer.append(" if ($3 == null)");
buffer.append(" {");
buffer.append(" paragraph = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" \" \",");
buffer.append(" new java.text.AttributedString(");
buffer.append(" $1, ");
buffer.append(" $2, ");
buffer.append(" $2 + 1");
buffer.append(" ).getIterator().getAttributes()");
buffer.append(" ).getIterator();");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" paragraph = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" $1, ");
buffer.append(" $2, ");
buffer.append(" $2 + $3.length()");
buffer.append(" ).getIterator();");
buffer.append(" }");
buffer.append("");
buffer.append(" java.awt.font.LineBreakMeasurer lineMeasurer = new java.awt.font.LineBreakMeasurer(paragraph, net.sf.jasperreports.engine.export.TextRenderer.LINE_BREAK_FONT_RENDER_CONTEXT);");
buffer.append(" ");
buffer.append(" while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached)");
buffer.append(" {");
buffer.append(" ");
buffer.append(" int startIndex = lineMeasurer.getPosition();");
buffer.append(" ");
buffer.append("");
buffer.append(" java.awt.font.TextLayout layout = lineMeasurer.nextLayout(formatWidth);");
buffer.append("");
buffer.append(" if (isMinimizePrinterJobSize)");
buffer.append(" {");
buffer.append(" ");
buffer.append(" java.text.AttributedString tmpText = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" paragraph, ");
buffer.append(" startIndex, ");
buffer.append(" startIndex + layout.getCharacterCount()");
buffer.append(" );");
buffer.append(" layout = new java.awt.font.TextLayout(tmpText.getIterator(), grx.getFontRenderContext());");
buffer.append(" ");
buffer.append(" }");
buffer.append("");
buffer.append(" float lineHeight = lineSpacingFactor * ");
buffer.append(" maxFontSizeFinder.findMaxFontSize(");
buffer.append(" new java.text.AttributedString(");
buffer.append(" paragraph, ");
buffer.append(" startIndex, ");
buffer.append(" startIndex + layout.getCharacterCount()");
buffer.append(" ).getIterator(),");
buffer.append(" fontSize");
buffer.append(" );");
buffer.append("");
buffer.append(" if (drawPosY + lineHeight <= textHeight)");
buffer.append(" {");
buffer.append(" drawPosY += lineHeight;");
buffer.append(" ");
buffer.append(" switch (horizontalAlignment)");
buffer.append(" {");
buffer.append(" case 4 :");
buffer.append(" {");
buffer.append(" if (layout.isLeftToRight())");
buffer.append(" {");
buffer.append(" drawPosX = 0;");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" drawPosX = formatWidth - layout.getAdvance();");
buffer.append(" }");
buffer.append(" if (lineMeasurer.getPosition() < paragraph.getEndIndex())");
buffer.append(" {");
buffer.append(" layout = layout.getJustifiedLayout(formatWidth);");
buffer.append(" }");
buffer.append("");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 3 :");
buffer.append(" {");
buffer.append(" drawPosX = formatWidth - layout.getAdvance();");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 2 :");
buffer.append(" {");
buffer.append(" drawPosX = (formatWidth - layout.getAdvance()) / 2;");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 1 :;");
buffer.append(" default :");
buffer.append(" {");
buffer.append(" drawPosX = 0;");
buffer.append(" }");
buffer.append(" }");
buffer.append("");
buffer.append(" draw(layout);");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" isMaxHeightReached = true;");
buffer.append(" }");
buffer.append(" }");
buffer.append(" }");

method
.setBody(new String(buffer));
cc.toClass();
}
}