AbstractPaddingOperator.java
package com.github.mygreen.supercsv.cellprocessor.conversion;
/**
* パディング処理の抽象クラス。
* <p>サロゲートペアを考慮します。</p>
*
* @since 2.1
* @author T.TSUCHIE
*
*/
public abstract class AbstractPaddingOperator implements PaddingProcessor {
/**
* コードポイントの配列に変換する。
* @param text
* @return
*/
private int[] toCodePointArray(final String text) {
final int length = text.length();
final int codePointLength = text.codePointCount(0, length);
int[] array = new int[codePointLength];
for(int i=0, j=0, codePoint=0; i < length; j++, i+=Character.charCount(codePoint)) {
codePoint = text.codePointAt(i);
array[j] = codePoint;
}
return array;
}
@Override
public String pad(final String text, final int size, final char padChar, final boolean rightAlign, final boolean chopped) {
final int currentSize = count(text);
final int padCharSize = count(String.valueOf(padChar));
final int[] codePointArray = toCodePointArray(text);
final int codePointSize = codePointArray.length;
if(rightAlign) {
// 右詰
if(currentSize == size) {
return text;
} else if(currentSize > size) {
// 指定した長さを超える場合
if(chopped) {
// 切り出す場合
/*
* 左端から長さをカウントしていき、オーバした長さ分を切り取る
*/
final int overLength = currentSize - size;
for(int i=0, chopLength=0; i < codePointSize; i++) {
final int codePoint = codePointArray[i];
chopLength += count(codePoint);
if(chopLength >= overLength) {
// substring(i+1)
String chopText = new String(codePointArray, i+1, codePointSize-(i+1));
// 切り取った後の再調整。
// パディング文字が全角の場合は、余分に切り取る場合があるため。
return pad(chopText, size, padChar, rightAlign, chopped);
}
}
// 全て切り出す場合
return "";
} else {
// 切り出さない場合
return text;
}
} else {
// 指定したサイズより少ない場合
/*
* パディング文字を付与していく
* ・パディング文字が全角の時があり、長さが2以上になるので注意する
*/
final int lackLength = size - currentSize;
int padCount = lackLength / padCharSize;
StringBuilder appender = new StringBuilder();
for(int i=0; i < padCount; i++) {
appender.append(padChar);
}
appender.append(text);
return appender.toString();
}
} else {
// 左詰
if(currentSize == size) {
return text;
} else if(currentSize > size) {
// 指定したサイズを超える場合
if(chopped) {
// 切り出す場合
/*
* 右端から長さをカウントしていき、オーバした長さ分を切り取る
*/
final int overLength = currentSize - size;
for(int i=codePointSize-1, chopLength=0; i >= 0; i--) {
final int codePoint = codePointArray[i];
chopLength += count(codePoint);
if(chopLength >= overLength) {
// substring(0, i)
String chopText = new String(codePointArray, 0, i);
// 切り取った後の再調整。
// パディング文字が全角の場合は、余分に切り取る場合があるため。
return pad(chopText, size, padChar, rightAlign, chopped);
}
}
// 全て切り出す場合
return "";
} else {
// 切り出さない場合
return text;
}
} else {
// 指定したサイズより少ない場合
/*
* パディング文字を付与していく
* ・パディング文字が全角の時があり、長さが2以上になるので注意する
*/
final int lackLength = size - currentSize;
int padCount = lackLength / padCharSize;
StringBuilder appender = new StringBuilder(text);
for(int i=0; i < padCount; i++) {
appender.append(padChar);
}
return appender.toString();
}
}
}
/**
* 文字数をカウントする
* @param codePoint カウント対象のコードポイント
* @return 文字数
*/
protected abstract int count(int codePoint);
/**
* 文字数をカウントする。
* @param text カウント対象の文字列
* @return 文字数
* @throws NullPointerException {@literal text is null.}
*/
protected abstract int count(String text);
}