diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5bf645d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+/.idea
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..075ed49
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "com.github.b1uec0in.androidjosaformatter"
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
+ testCompile 'junit:junit:4.12'
+
+ compile project(path: ':josaformatter')
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..089b1a0
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/1100388/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/com/github/b1uec0in/androidjosaformatter/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/github/b1uec0in/androidjosaformatter/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..9b12842
--- /dev/null
+++ b/app/src/androidTest/java/com/github/b1uec0in/androidjosaformatter/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.github.b1uec0in.androidjosaformatter;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.github.b1uec0in.androidjosaformatter", appContext.getPackageName());
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..822f4fb
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/github/b1uec0in/androidjosaformatter/MainActivity.java b/app/src/main/java/com/github/b1uec0in/androidjosaformatter/MainActivity.java
new file mode 100644
index 0000000..bfdd545
--- /dev/null
+++ b/app/src/main/java/com/github/b1uec0in/androidjosaformatter/MainActivity.java
@@ -0,0 +1,32 @@
+package com.github.b1uec0in.androidjosaformatter;
+
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+import com.github.b1uec0in.josaformatter.KoreanUtils;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public void onButtonClick(View view) {
+ EditText nickNameEditText = (EditText)findViewById(R.id.nickNameEditText);
+
+ String nickName = nickNameEditText.getText().toString();
+
+ String message;
+ if (nickName.length() > 0) {
+ message = KoreanUtils.format(getString(R.string.nick_name_confirm_format), nickName);
+ } else {
+ message = getString(R.string.nick_name_hint);
+ }
+ new AlertDialog.Builder(this).setMessage(message).setPositiveButton(android.R.string.ok, null).show();
+ }
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..4605371
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e83a75d
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+
+ AndroidJosaFormatter
+ 입력한 닉네임에 따라 메시지의 조사(을,를)를 교정합니다.
+ 닉네임을 입력하세요.
+ \'%s\'를 입력했습니다.
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..daa2a5c
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/com/github/b1uec0in/androidjosaformatter/ExampleUnitTest.java b/app/src/test/java/com/github/b1uec0in/androidjosaformatter/ExampleUnitTest.java
new file mode 100644
index 0000000..ba1f2d0
--- /dev/null
+++ b/app/src/test/java/com/github/b1uec0in/androidjosaformatter/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.github.b1uec0in.androidjosaformatter;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..b78a0b8
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..ce858d9
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed May 24 16:22:48 KST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/josaformatter/.gitignore b/josaformatter/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/josaformatter/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/josaformatter/build.gradle b/josaformatter/build.gradle
new file mode 100644
index 0000000..ff03b0d
--- /dev/null
+++ b/josaformatter/build.gradle
@@ -0,0 +1,31 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/josaformatter/proguard-rules.pro b/josaformatter/proguard-rules.pro
new file mode 100644
index 0000000..089b1a0
--- /dev/null
+++ b/josaformatter/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/1100388/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/josaformatter/src/androidTest/java/com/github/b1uec0in/josaformatter/ExampleInstrumentedTest.java b/josaformatter/src/androidTest/java/com/github/b1uec0in/josaformatter/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..de73e2f
--- /dev/null
+++ b/josaformatter/src/androidTest/java/com/github/b1uec0in/josaformatter/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.github.b1uec0in.josaformatter;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.github.b1uec0in.koreanutils.test", appContext.getPackageName());
+ }
+}
diff --git a/josaformatter/src/main/AndroidManifest.xml b/josaformatter/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ebbfdee
--- /dev/null
+++ b/josaformatter/src/main/AndroidManifest.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/CharUtils.java b/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/CharUtils.java
new file mode 100644
index 0000000..344cff2
--- /dev/null
+++ b/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/CharUtils.java
@@ -0,0 +1,45 @@
+package com.github.b1uec0in.josaformatter;
+
+/**
+ * Created by yjbae@sk.com on 2017/05/24.
+ */
+
+class CharUtils {
+ public static boolean isAlpha(char ch) {
+ return isAlphaLowerCase(ch) || isAlphaUpperCase(ch);
+ }
+
+ public static boolean isAlphaLowerCase(char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ public static boolean isAlphaUpperCase(char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ public static boolean isNumber(char ch) {
+ return ch >= '0' && ch <= '9';
+ }
+
+ public static boolean isHangulFullChar(char ch) {
+ return ch >= 0xac00 && ch <= 0xd7af;
+ }
+
+ public static boolean hasHangulJongSung(char ch) {
+ return isHangulFullChar(ch) && (ch - 0xAC00) % 28 > 0;
+ }
+
+ // String manipulation
+ public static char lastChar(CharSequence charSequence) {
+ if (charSequence == null) {
+ return '\0';
+ }
+ int length = charSequence.length();
+ if (length == 0) {
+ return '\0';
+ }
+
+ return charSequence.charAt(length - 1);
+ }
+
+}
diff --git a/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/Formatter.java b/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/Formatter.java
new file mode 100644
index 0000000..03670d2
--- /dev/null
+++ b/josaformatter/src/main/java/com/github/b1uec0in/josaformatter/Formatter.java
@@ -0,0 +1,3371 @@
+package com.github.b1uec0in.josaformatter;
+
+/**
+ * Created by yjbae@sk.com on 2017/05/23.
+ */
+
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.DuplicateFormatFlagsException;
+import java.util.FormatFlagsConversionMismatchException;
+import java.util.FormatterClosedException;
+import java.util.IllegalFormatCodePointException;
+import java.util.IllegalFormatConversionException;
+import java.util.IllegalFormatFlagsException;
+import java.util.IllegalFormatPrecisionException;
+import java.util.IllegalFormatWidthException;
+import java.util.Locale;
+import java.util.MissingFormatArgumentException;
+import java.util.MissingFormatWidthException;
+import java.util.UnknownFormatConversionException;
+import java.util.UnknownFormatFlagsException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * An interpreter for printf-style format strings. This class provides support
+ * for layout justification and alignment, common formats for numeric, string,
+ * and date/time data, and locale-specific output. Common Java types such as
+ * byte, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
+ * are supported. Limited formatting customization for arbitrary user types is
+ * provided through the {@link Formattable} interface.
+ *
+ *
Formatters are not necessarily safe for multithreaded access. Thread
+ * safety is optional and is the responsibility of users of methods in this
+ * class.
+ *
+ *
Formatted printing for the Java language is heavily inspired by C's
+ * printf. Although the format strings are similar to C, some
+ * customizations have been made to accommodate the Java language and exploit
+ * some of its features. Also, Java formatting is more strict than C's; for
+ * example, if a conversion is incompatible with a flag, an exception will be
+ * thrown. In C inapplicable flags are silently ignored. The format strings
+ * are thus intended to be recognizable to C programmers but not necessarily
+ * completely compatible with those in C.
+ *
+ *
Examples of expected usage:
+ *
+ *
+ * StringBuilder sb = new StringBuilder();
+ * // Send all output to the Appendable object sb
+ * Formatter formatter = new Formatter(sb, Locale.US);
+ *
+ * // Explicit argument indices may be used to re-order output.
+ * formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
+ * // -> " d c b a"
+ *
+ * // Optional locale as the first argument can be used to get
+ * // locale-specific formatting of numbers. The precision and width can be
+ * // given to round and align the value.
+ * formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
+ * // -> "e = +2,7183"
+ *
+ * // The '(' numeric flag may be used to format negative numbers with
+ * // parentheses rather than a minus sign. Group separators are
+ * // automatically inserted.
+ * formatter.format("Amount gained or lost since last statement: $ %(,.2f",
+ * balanceDelta);
+ * // -> "Amount gained or lost since last statement: $ (6,217.58)"
+ *
+ *
+ *
Convenience methods for common formatting requests exist as illustrated
+ * by the following invocations:
+ *
+ *
+ * // Writes a formatted string to System.out.
+ * System.out.format("Local time: %tT", Calendar.getInstance());
+ * // -> "Local time: 13:34:18"
+ *
+ * // Writes formatted output to System.err.
+ * System.err.printf("Unable to open file '%1$s': %2$s",
+ * fileName, exception.getMessage());
+ * // -> "Unable to open file 'food': No such file or directory"
+ *
+ *
+ *
Like C's sprintf(3), Strings may be formatted using the static
+ * method {@link String#format(String,Object...) String.format}:
+ *
+ *
+ * // Format a string containing a date.
+ * import java.util.Calendar;
+ * import java.util.GregorianCalendar;
+ * import static java.util.Calendar.*;
+ *
+ * Calendar c = new GregorianCalendar(1995, MAY, 23);
+ * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ * // -> s == "Duke's Birthday: May 23, 1995"
+ *
This specification is divided into two sections. The first section, Summary, covers the basic formatting concepts. This
+ * section is intended for users who want to get started quickly and are
+ * familiar with formatted printing in other programming languages. The second
+ * section, Details, covers the specific implementation
+ * details. It is intended for users who want more precise specification of
+ * formatting behavior.
+ *
+ *
Every method which produces formatted output requires a format
+ * string and an argument list. The format string is a {@link
+ * String} which may contain fixed text and one or more embedded format
+ * specifiers. Consider the following example:
+ *
+ *
+ * Calendar c = ...;
+ * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ *
+ *
+ * This format string is the first argument to the format method. It
+ * contains three format specifiers "%1$tm", "%1$te", and
+ * "%1$tY" which indicate how the arguments should be processed and
+ * where they should be inserted in the text. The remaining portions of the
+ * format string are fixed text including "Dukes Birthday: " and any
+ * other spaces or punctuation.
+ *
+ * The argument list consists of all arguments passed to the method after the
+ * format string. In the above example, the argument list is of size one and
+ * consists of the {@link java.util.Calendar Calendar} object c.
+ *
+ *
+ *
+ *
The format specifiers for general, character, and numeric types have
+ * the following syntax:
+ *
+ *
The optional argument_index is a decimal integer indicating the
+ * position of the argument in the argument list. The first argument is
+ * referenced by "1$", the second by "2$", etc.
+ *
+ *
The optional flags is a set of characters that modify the output
+ * format. The set of valid flags depends on the conversion.
+ *
+ *
The optional width is a non-negative decimal integer indicating
+ * the minimum number of characters to be written to the output.
+ *
+ *
The optional precision is a non-negative decimal integer usually
+ * used to restrict the number of characters. The specific behavior depends on
+ * the conversion.
+ *
+ *
The required conversion is a character indicating how the
+ * argument should be formatted. The set of valid conversions for a given
+ * argument depends on the argument's data type.
+ *
+ *
The format specifiers for types which are used to represents dates and
+ * times have the following syntax:
+ *
+ *
The optional argument_index, flags and width are
+ * defined as above.
+ *
+ *
The required conversion is a two character sequence. The first
+ * character is 't' or 'T'. The second character indicates
+ * the format to be used. These characters are similar to but not completely
+ * identical to those defined by GNU date and POSIX
+ * strftime(3c).
+ *
+ *
The format specifiers which do not correspond to arguments have the
+ * following syntax:
+ *
+ *
+ * %[flags][width]conversion
+ *
+ *
+ *
The optional flags and width is defined as above.
+ *
+ *
The required conversion is a character indicating content to be
+ * inserted in the output.
+ *
+ *
+ *
+ *
Conversions
+ *
+ *
Conversions are divided into the following categories:
+ *
+ *
+ *
+ *
General - may be applied to any argument
+ * type
+ *
+ *
Character - may be applied to basic types which represent
+ * Unicode characters: char, {@link Character}, byte, {@link
+ * Byte}, short, and {@link Short}. This conversion may also be
+ * applied to the types int and {@link Integer} when {@link
+ * Character#isValidCodePoint} returns true
+ *
+ *
Numeric
+ *
+ *
+ *
+ *
Integral - may be applied to Java integral types: byte,
+ * {@link Byte}, short, {@link Short}, int and {@link
+ * Integer}, long, {@link Long}, and {@link java.math.BigInteger
+ * BigInteger}
+ *
+ *
Floating Point - may be applied to Java floating-point types:
+ * float, {@link Float}, double, {@link Double}, and {@link
+ * java.math.BigDecimal BigDecimal}
+ *
+ *
+ *
+ *
Date/Time - may be applied to Java types which are capable of
+ * encoding a date or time: long, {@link Long}, {@link Calendar}, and
+ * {@link Date}.
+ *
+ *
Line Separator - produces the platform-specific line separator
+ *
+ *
+ *
+ *
The following table summarizes the supported conversions. Conversions
+ * denoted by an upper-case character (i.e. 'B', 'H',
+ * 'S', 'C', 'X', 'E', 'G',
+ * 'A', and 'T') are the same as those for the corresponding
+ * lower-case conversion characters except that the result is converted to
+ * upper case according to the rules of the prevailing {@link java.util.Locale
+ * Locale}. The result is equivalent to the following invocation of {@link
+ * String#toUpperCase()}
+ *
+ *
+ * out.toUpperCase()
+ *
+ *
+ *
+ *
Conversion
+ *
Argument Category
+ *
Description
+ *
+ *
'b', 'B'
+ *
general
+ *
If the argument arg is null, then the result is
+ * "false". If arg is a boolean or {@link
+ * Boolean}, then the result is the string returned by {@link
+ * String#valueOf(boolean) String.valueOf(arg)}. Otherwise, the result is
+ * "true".
+ *
+ *
'h', 'H'
+ *
general
+ *
If the argument arg is null, then the result is
+ * "null". Otherwise, the result is obtained by invoking
+ * Integer.toHexString(arg.hashCode()).
+ *
+ *
's', 'S'
+ *
general
+ *
If the argument arg is null, then the result is
+ * "null". If arg implements {@link Formattable}, then
+ * {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the
+ * result is obtained by invoking arg.toString().
+ *
+ *
'c', 'C'
+ *
character
+ *
The result is a Unicode character
+ *
+ *
'd'
+ *
integral
+ *
The result is formatted as a decimal integer
+ *
+ *
'o'
+ *
integral
+ *
The result is formatted as an octal integer
+ *
+ *
'x', 'X'
+ *
integral
+ *
The result is formatted as a hexadecimal integer
+ *
+ *
'e', 'E'
+ *
floating point
+ *
The result is formatted as a decimal number in computerized
+ * scientific notation
+ *
+ *
'f'
+ *
floating point
+ *
The result is formatted as a decimal number
+ *
+ *
'g', 'G'
+ *
floating point
+ *
The result is formatted using computerized scientific notation or
+ * decimal format, depending on the precision and the value after rounding.
+ *
+ *
'a', 'A'
+ *
floating point
+ *
The result is formatted as a hexadecimal floating-point number with
+ * a significand and an exponent
+ *
+ *
The following date and time conversion suffix characters are defined for
+ * the 't' and 'T' conversions. The types are similar to but
+ * not completely identical to those defined by GNU date and POSIX
+ * strftime(3c). Additional conversion types are provided to access
+ * Java-specific functionality (e.g. 'L' for milliseconds within the
+ * second).
+ *
+ *
The following conversion characters are used for formatting times:
+ *
+ *
+ *
+ *
'H'
+ *
Hour of the day for the 24-hour clock, formatted as two digits with
+ * a leading zero as necessary i.e. 00 - 23.
+ *
+ *
'I'
+ *
Hour for the 12-hour clock, formatted as two digits with a leading
+ * zero as necessary, i.e. 01 - 12.
+ *
+ *
'k'
+ *
Hour of the day for the 24-hour clock, i.e. 0 - 23.
+ *
+ *
'l'
+ *
Hour for the 12-hour clock, i.e. 1 - 12.
+ *
+ *
'M'
+ *
Minute within the hour formatted as two digits with a leading zero
+ * as necessary, i.e. 00 - 59.
+ *
+ *
'S'
+ *
Seconds within the minute, formatted as two digits with a leading
+ * zero as necessary, i.e. 00 - 60 ("60" is a special
+ * value required to support leap seconds).
+ *
+ *
'L'
+ *
Millisecond within the second formatted as three digits with
+ * leading zeros as necessary, i.e. 000 - 999.
+ *
+ *
'N'
+ *
Nanosecond within the second, formatted as nine digits with leading
+ * zeros as necessary, i.e. 000000000 - 999999999.
+ *
+ *
'p'
+ *
Locale-specific {@linkplain
+ * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ * in lower case, e.g."am" or "pm". Use of the conversion
+ * prefix 'T' forces this output to upper case.
+ *
+ *
'z'
+ *
RFC 822
+ * style numeric time zone offset from GMT, e.g. -0800.
+ *
+ *
'Z'
+ *
A string representing the abbreviation for the time zone. The
+ * Formatter's locale will supersede the locale of the argument (if any).
+ *
+ *
's'
+ *
Seconds since the beginning of the epoch starting at 1 January 1970
+ * 00:00:00 UTC, i.e. Long.MIN_VALUE/1000 to
+ * Long.MAX_VALUE/1000.
+ *
+ *
'Q'
+ *
Milliseconds since the beginning of the epoch starting at 1 January
+ * 1970 00:00:00 UTC, i.e. Long.MIN_VALUE to
+ * Long.MAX_VALUE.
+ *
+ *
+ *
+ *
The following conversion characters are used for formatting dates:
+ *
+ *
+ *
+ *
'B'
+ *
Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ * full month name}, e.g. "January", "February".
+ *
+ *
Locale-specific full name of the {@linkplain
+ * java.text.DateFormatSymbols#getWeekdays day of the week},
+ * e.g. "Sunday", "Monday"
+ *
+ *
'a'
+ *
Locale-specific short name of the {@linkplain
+ * java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ * e.g. "Sun", "Mon"
+ *
+ *
'C'
+ *
Four-digit year divided by 100, formatted as two digits
+ * with leading zero as necessary, i.e. 00 - 99
+ *
+ *
'Y'
+ *
Year, formatted as at least four digits with leading zeros as
+ * necessary, e.g. 0092 equals 92 CE for the Gregorian
+ * calendar.
+ *
+ *
'y'
+ *
Last two digits of the year, formatted with leading zeros as
+ * necessary, i.e. 00 - 99.
+ *
+ *
'j'
+ *
Day of year, formatted as three digits with leading zeros as
+ * necessary, e.g. 001 - 366 for the Gregorian calendar.
+ *
+ *
'm'
+ *
Month, formatted as two digits with leading zeros as necessary,
+ * i.e. 01 - 13.
+ *
+ *
'd'
+ *
Day of month, formatted as two digits with leading zeros as
+ * necessary, i.e. 01 - 31
+ *
+ *
'e'
+ *
Day of month, formatted as two digits, i.e. 1 - 31.
+ *
+ *
+ *
+ *
The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ *
+ *
+ *
'R'
+ *
Time formatted for the 24-hour clock as "%tH:%tM"
+ *
+ *
'T'
+ *
Time formatted for the 24-hour clock as "%tH:%tM:%tS".
+ *
+ *
'r'
+ *
Time formatted for the 12-hour clock as "%tI:%tM:%tS %Tp".
+ * The location of the morning or afternoon marker ('%Tp') may be
+ * locale-dependent.
+ *
+ *
'D'
+ *
Date formatted as "%tm/%td/%ty".
+ *
+ *
'F'
+ *
ISO 8601
+ * complete date formatted as "%tY-%tm-%td".
+ *
+ *
'c'
+ *
Date and time formatted as "%ta %tb %td %tT %tZ %tY",
+ * e.g. "Sun Jul 20 16:17:00 EDT 1969".
+ *
+ *
+ *
+ *
Any characters not explicitly defined as date/time conversion suffixes
+ * are illegal and are reserved for future extensions.
+ *
+ *
Flags
+ *
+ *
The following table summarizes the supported flags. y means the
+ * flag is supported for the indicated argument types.
+ *
+ *
+ *
+ *
Flag
General
+ *
Character
Integral
+ *
Floating Point
+ *
Date/Time
+ *
Description
+ *
+ *
'-'
y
+ *
y
+ *
y
+ *
y
+ *
y
+ *
The result will be left-justified.
+ *
+ *
'#'
y1
+ *
-
+ *
y3
+ *
y
+ *
-
+ *
The result should use a conversion-dependent alternate form
+ *
+ *
'+'
-
+ *
-
+ *
y4
+ *
y
+ *
-
+ *
The result will always include a sign
+ *
+ *
' '
-
+ *
-
+ *
y4
+ *
y
+ *
-
+ *
The result will include a leading space for positive values
+ *
+ *
'0'
-
+ *
-
+ *
y
+ *
y
+ *
-
+ *
The result will be zero-padded
+ *
+ *
','
-
+ *
-
+ *
y2
+ *
y5
+ *
-
+ *
The result will include locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators}
+ *
+ *
'('
-
+ *
-
+ *
y4
+ *
y5
+ *
-
+ *
The result will enclose negative numbers in parentheses
+ *
+ *
+ *
+ *
1 Depends on the definition of {@link Formattable}.
+ *
+ *
2 For 'd' conversion only.
+ *
+ *
3 For 'o', 'x', and 'X'
+ * conversions only.
+ *
+ *
4 For 'd', 'o', 'x', and
+ * 'X' conversions applied to {@link java.math.BigInteger BigInteger}
+ * or 'd' applied to byte, {@link Byte}, short, {@link
+ * Short}, int and {@link Integer}, long, and {@link Long}.
+ *
+ *
5 For 'e', 'E', 'f',
+ * 'g', and 'G' conversions only.
+ *
+ *
Any characters not explicitly defined as flags are illegal and are
+ * reserved for future extensions.
+ *
+ *
Width
+ *
+ *
The width is the minimum number of characters to be written to the
+ * output. For the line separator conversion, width is not applicable; if it
+ * is provided, an exception will be thrown.
+ *
+ *
Precision
+ *
+ *
For general argument types, the precision is the maximum number of
+ * characters to be written to the output.
+ *
+ *
For the floating-point conversions 'e', 'E', and
+ * 'f' the precision is the number of digits after the decimal
+ * separator. If the conversion is 'g' or 'G', then the
+ * precision is the total number of digits in the resulting magnitude after
+ * rounding. If the conversion is 'a' or 'A', then the
+ * precision must not be specified.
+ *
+ *
For character, integral, and date/time argument types and the percent
+ * and line separator conversions, the precision is not applicable; if a
+ * precision is provided, an exception will be thrown.
+ *
+ *
Argument Index
+ *
+ *
The argument index is a decimal integer indicating the position of the
+ * argument in the argument list. The first argument is referenced by
+ * "1$", the second by "2$", etc.
+ *
+ *
Another way to reference arguments by position is to use the
+ * '<' ('\u003c') flag, which causes the argument for
+ * the previous format specifier to be re-used. For example, the following two
+ * statements would produce identical strings:
+ *
+ *
This section is intended to provide behavioral details for formatting,
+ * including conditions and exceptions, supported data types, localization, and
+ * interactions between flags, conversions, and data types. For an overview of
+ * formatting concepts, refer to the Summary
+ *
+ *
Any characters not explicitly defined as conversions, date/time
+ * conversion suffixes, or flags are illegal and are reserved for
+ * future extensions. Use of such a character in a format string will
+ * cause an {@link UnknownFormatConversionException} or {@link
+ * UnknownFormatFlagsException} to be thrown.
+ *
+ *
If the format specifier contains a width or precision with an invalid
+ * value or which is otherwise unsupported, then a {@link
+ * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
+ * respectively will be thrown.
+ *
+ *
If a format specifier contains a conversion character that is not
+ * applicable to the corresponding argument, then an {@link
+ * IllegalFormatConversionException} will be thrown.
+ *
+ *
All specified exceptions may be thrown by any of the format
+ * methods of Formatter as well as by any format convenience
+ * methods such as {@link String#format(String,Object...) String.format} and
+ * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}.
+ *
+ *
Conversions denoted by an upper-case character (i.e. 'B',
+ * 'H', 'S', 'C', 'X', 'E',
+ * 'G', 'A', and 'T') are the same as those for the
+ * corresponding lower-case conversion characters except that the result is
+ * converted to upper case according to the rules of the prevailing {@link
+ * java.util.Locale Locale}. The result is equivalent to the following
+ * invocation of {@link String#toUpperCase()}
+ *
+ *
The following general conversions may be applied to any argument type:
+ *
+ *
+ *
+ *
'b'
+ *
'\u0062'
+ *
Produces either "true" or "false" as returned by
+ * {@link Boolean#toString(boolean)}.
+ *
+ *
If the argument is null, then the result is
+ * "false". If the argument is a boolean or {@link
+ * Boolean}, then the result is the string returned by {@link
+ * String#valueOf(boolean) String.valueOf()}. Otherwise, the result is
+ * "true".
+ *
+ *
If the '#' flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'B'
+ *
'\u0042'
+ *
The upper-case variant of 'b'.
+ *
+ *
'h'
+ *
'\u0068'
+ *
Produces a string representing the hash code value of the object.
+ *
+ *
If the argument, arg is null, then the
+ * result is "null". Otherwise, the result is obtained
+ * by invoking Integer.toHexString(arg.hashCode()).
+ *
+ *
If the '#' flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'H'
+ *
'\u0048'
+ *
The upper-case variant of 'h'.
+ *
+ *
's'
+ *
'\u0073'
+ *
Produces a string.
+ *
+ *
If the argument is null, then the result is
+ * "null". If the argument implements {@link Formattable}, then
+ * its {@link Formattable#formatTo formatTo} method is invoked.
+ * Otherwise, the result is obtained by invoking the argument's
+ * toString() method.
+ *
+ *
If the '#' flag is given and the argument is not a {@link
+ * Formattable} , then a {@link FormatFlagsConversionMismatchException}
+ * will be thrown.
+ *
+ *
'S'
+ *
'\u0053'
+ *
The upper-case variant of 's'.
+ *
+ *
+ *
+ *
The following flags apply to general conversions:
+ *
+ *
+ *
+ *
'-'
+ *
'\u002d'
+ *
Left justifies the output. Spaces ('\u0020') will be
+ * added at the end of the converted value as required to fill the minimum
+ * width of the field. If the width is not provided, then a {@link
+ * MissingFormatWidthException} will be thrown. If this flag is not given
+ * then the output will be right-justified.
+ *
+ *
'#'
+ *
'\u0023'
+ *
Requires the output use an alternate form. The definition of the
+ * form is specified by the conversion.
+ *
+ *
+ *
+ *
The width is the minimum number of characters to
+ * be written to the
+ * output. If the length of the converted value is less than the width then
+ * the output will be padded by ' ' (\u0020')
+ * until the total number of characters equals the width. The padding is on
+ * the left by default. If the '-' flag is given, then the padding
+ * will be on the right. If the width is not specified then there is no
+ * minimum.
+ *
+ *
The precision is the maximum number of characters to be written to the
+ * output. The precision is applied before the width, thus the output will be
+ * truncated to precision characters even if the width is greater than
+ * the precision. If the precision is not specified then there is no explicit
+ * limit on the number of characters.
+ *
+ *
+ *
+ * This conversion may be applied to char and {@link Character}. It
+ * may also be applied to the types byte, {@link Byte},
+ * short, and {@link Short}, int and {@link Integer} when
+ * {@link Character#isValidCodePoint} returns true. If it returns
+ * false then an {@link IllegalFormatCodePointException} will be
+ * thrown.
+ *
+ *
+ *
+ *
'c'
+ *
'\u0063'
+ *
Formats the argument as a Unicode character as described in Unicode Character
+ * Representation. This may be more than one 16-bit char in
+ * the case where the argument represents a supplementary character.
+ *
+ *
If the '#' flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'C'
+ *
'\u0043'
+ *
The upper-case variant of 'c'.
+ *
+ *
+ *
+ *
The '-' flag defined for General
+ * conversions applies. If the '#' flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
After digits are obtained for the integer part, fractional part, and
+ * exponent (as appropriate for the data type), the following transformation
+ * is applied:
+ *
+ *
+ *
+ *
Each digit character d in the string is replaced by a
+ * locale-specific digit computed relative to the current locale's
+ * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit}
+ * z; that is d - '0'
+ * + z.
+ *
+ *
If a decimal separator is present, a locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is
+ * substituted.
+ *
+ *
If the ',' ('\u002c')
+ * flag is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
+ * inserted by scanning the integer part of the string from least significant
+ * to most significant digits and inserting a separator at intervals defined by
+ * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping
+ * size}.
+ *
+ *
If the '0' flag is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted
+ * after the sign character, if any, and before the first non-zero digit, until
+ * the length of the string is equal to the requested field width.
+ *
+ *
If the value is negative and the '(' flag is given, then a
+ * '(' ('\u0028') is prepended and a ')'
+ * ('\u0029') is appended.
+ *
+ *
If the value is negative (or floating-point negative zero) and
+ * '(' flag is not given, then a '-' ('\u002d')
+ * is prepended.
+ *
+ *
If the '+' flag is given and the value is positive or zero (or
+ * floating-point positive zero), then a '+' ('\u002b')
+ * will be prepended.
+ *
+ *
+ *
+ *
If the value is NaN or positive infinity the literal strings "NaN" or
+ * "Infinity" respectively, will be output. If the value is negative infinity,
+ * then the output will be "(Infinity)" if the '(' flag is given
+ * otherwise the output will be "-Infinity". These values are not localized.
+ *
+ *
The following conversions may be applied to byte, {@link Byte},
+ * short, {@link Short}, int and {@link Integer},
+ * long, and {@link Long}.
+ *
+ *
+ *
+ *
'd'
+ *
'\u0054'
+ *
Formats the argument as a decimal integer. The localization algorithm is applied.
+ *
+ *
If the '0' flag is given and the value is negative, then
+ * the zero padding will occur after the sign.
+ *
+ *
If the '#' flag is given then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'o'
+ *
'\u006f'
+ *
Formats the argument as an integer in base eight. No localization
+ * is applied.
+ *
+ *
If x is negative then the result will be an unsigned value
+ * generated by adding 2n to the value where n is the
+ * number of bits in the type as returned by the static SIZE field
+ * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ * classes as appropriate.
+ *
+ *
If the '#' flag is given then the output will always begin
+ * with the radix indicator '0'.
+ *
+ *
If the '0' flag is given then the output will be padded
+ * with leading zeros to the field width following any indication of sign.
+ *
+ *
If '(', '+', '  ', or ',' flags
+ * are given then a {@link FormatFlagsConversionMismatchException} will be
+ * thrown.
+ *
+ *
'x'
+ *
'\u0078'
+ *
Formats the argument as an integer in base sixteen. No
+ * localization is applied.
+ *
+ *
If x is negative then the result will be an unsigned value
+ * generated by adding 2n to the value where n is the
+ * number of bits in the type as returned by the static SIZE field
+ * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ * classes as appropriate.
+ *
+ *
If the '#' flag is given then the output will always begin
+ * with the radix indicator "0x".
+ *
+ *
If the '0' flag is given then the output will be padded to
+ * the field width with leading zeros after the radix indicator or sign (if
+ * present).
+ *
+ *
If '(', ' ', '+', or
+ * ',' flags are given then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'X'
+ *
'\u0058'
+ *
The upper-case variant of 'x'. The entire string
+ * representing the number will be converted to {@linkplain
+ * String#toUpperCase upper case} including the 'x' (if any) and
+ * all hexadecimal digits 'a' - 'f'
+ * ('\u0061' - '\u0066').
+ *
+ *
+ *
+ *
If the conversion is 'o', 'x', or 'X' and
+ * both the '#' and the '0' flags are given, then result will
+ * contain the radix indicator ('0' for octal and "0x" or
+ * "0X" for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ *
If the '-' flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ *
The following flags apply to numeric integral
+ * conversions:
+ *
+ *
+ *
+ *
'+'
+ *
'\u002b'
+ *
Requires the output to include a positive sign for all positive
+ * numbers. If this flag is not given then only negative values will
+ * include a sign.
+ *
+ *
If both the '+' and ' ' flags are given
+ * then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ *
' '
+ *
'\u0020'
+ *
Requires the output to include a single extra space
+ * ('\u0020') for non-negative values.
+ *
+ *
If both the '+' and ' ' flags are given
+ * then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ *
'0'
+ *
'\u0030'
+ *
Requires the output to be padded with leading {@linkplain
+ * java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field
+ * width following any sign or radix indicator except when converting NaN
+ * or infinity. If the width is not provided, then a {@link
+ * MissingFormatWidthException} will be thrown.
+ *
+ *
If both the '-' and '0' flags are given then an
+ * {@link IllegalFormatFlagsException} will be thrown.
+ *
+ *
','
+ *
'\u002c'
+ *
Requires the output to include the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
+ * described in the "group" section of the
+ * localization algorithm.
+ *
+ *
'('
+ *
'\u0028'
+ *
Requires the output to prepend a '('
+ * ('\u0028') and append a ')'
+ * ('\u0029') to negative values.
+ *
+ *
+ *
+ *
If no flags are given the default formatting is
+ * as follows:
+ *
+ *
+ *
+ *
The output is right-justified within the width
+ *
+ *
Negative numbers begin with a '-' ('\u002d')
+ *
+ *
Positive numbers and zero do not include a sign or extra leading
+ * space
+ *
+ *
No grouping separators are included
+ *
+ *
+ *
+ *
The width is the minimum number of characters to
+ * be written to the output. This includes any signs, digits, grouping
+ * separators, radix indicator, and parentheses. If the length of the
+ * converted value is less than the width then the output will be padded by
+ * spaces ('\u0020') until the total number of characters equals
+ * width. The padding is on the left by default. If '-' flag is
+ * given then the padding will be on the right. If width is not specified then
+ * there is no minimum.
+ *
+ *
The precision is not applicable. If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ *
The following conversions may be applied to {@link
+ * java.math.BigInteger}.
+ *
+ *
+ *
+ *
'd'
+ *
'\u0054'
+ *
Requires the output to be formatted as a decimal integer. The localization algorithm is applied.
+ *
+ *
If the '#' flag is given {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'o'
+ *
'\u006f'
+ *
Requires the output to be formatted as an integer in base eight.
+ * No localization is applied.
+ *
+ *
If x is negative then the result will be a signed value
+ * beginning with '-' ('\u002d'). Signed output is
+ * allowed for this type because unlike the primitive types it is not
+ * possible to create an unsigned equivalent without assuming an explicit
+ * data-type size.
+ *
+ *
If x is positive or zero and the '+' flag is given
+ * then the result will begin with '+' ('\u002b').
+ *
+ *
If the '#' flag is given then the output will always begin
+ * with '0' prefix.
+ *
+ *
If the '0' flag is given then the output will be padded
+ * with leading zeros to the field width following any indication of sign.
+ *
+ *
If the ',' flag is given then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'x'
+ *
'\u0078'
+ *
Requires the output to be formatted as an integer in base
+ * sixteen. No localization is applied.
+ *
+ *
If x is negative then the result will be a signed value
+ * beginning with '-' ('\u002d'). Signed output is
+ * allowed for this type because unlike the primitive types it is not
+ * possible to create an unsigned equivalent without assuming an explicit
+ * data-type size.
+ *
+ *
If x is positive or zero and the '+' flag is given
+ * then the result will begin with '+' ('\u002b').
+ *
+ *
If the '#' flag is given then the output will always begin
+ * with the radix indicator "0x".
+ *
+ *
If the '0' flag is given then the output will be padded to
+ * the field width with leading zeros after the radix indicator or sign (if
+ * present).
+ *
+ *
If the ',' flag is given then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'X'
+ *
'\u0058'
+ *
The upper-case variant of 'x'. The entire string
+ * representing the number will be converted to {@linkplain
+ * String#toUpperCase upper case} including the 'x' (if any) and
+ * all hexadecimal digits 'a' - 'f'
+ * ('\u0061' - '\u0066').
+ *
+ *
+ *
+ *
If the conversion is 'o', 'x', or 'X' and
+ * both the '#' and the '0' flags are given, then result will
+ * contain the base indicator ('0' for octal and "0x" or
+ * "0X" for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ *
If the '0' flag is given and the value is negative, then the
+ * zero padding will occur after the sign.
+ *
+ *
If the '-' flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ *
All flags defined for Byte, Short, Integer, and
+ * Long apply. The default behavior when no flags are
+ * given is the same as for Byte, Short, Integer, and Long.
+ *
+ *
The specification of width is the same as
+ * defined for Byte, Short, Integer, and Long.
+ *
+ *
The precision is not applicable. If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ *
The formatting of the magnitude m depends upon its value.
+ *
+ *
If m is NaN or infinite, the literal strings "NaN" or
+ * "Infinity", respectively, will be output. These values are not
+ * localized.
+ *
+ *
If m is positive-zero or negative-zero, then the exponent
+ * will be "+00".
+ *
+ *
Otherwise, the result is a string that represents the sign and
+ * magnitude (absolute value) of the argument. The formatting of the sign
+ * is described in the localization
+ * algorithm. The formatting of the magnitude m depends upon its
+ * value.
+ *
+ *
Let n be the unique integer such that 10n
+ * <= m < 10n+1; then let a be the
+ * mathematically exact quotient of m and 10n so
+ * that 1 <= a < 10. The magnitude is then represented as the
+ * integer part of a, as a single decimal digit, followed by the
+ * decimal separator followed by decimal digits representing the fractional
+ * part of a, followed by the exponent symbol 'e'
+ * ('\u0065'), followed by the sign of the exponent, followed
+ * by a representation of n as a decimal integer, as produced by the
+ * method {@link Long#toString(long, int)}, and zero-padded to include at
+ * least two digits.
+ *
+ *
The number of digits in the result for the fractional part of
+ * m or a is equal to the precision. If the precision is not
+ * specified then the default value is 6. If the precision is less
+ * than the number of digits which would appear after the decimal point in
+ * the string returned by {@link Float#toString(float)} or {@link
+ * Double#toString(double)} respectively, then the value will be rounded
+ * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * algorithm}. Otherwise, zeros may be appended to reach the precision.
+ * For a canonical representation of the value, use {@link
+ * Float#toString(float)} or {@link Double#toString(double)} as
+ * appropriate.
+ *
+ *
If the ',' flag is given, then an {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'E'
+ *
'\u0045'
+ *
The upper-case variant of 'e'. The exponent symbol
+ * will be 'E' ('\u0045').
+ *
+ *
'g'
+ *
'\u0067'
+ *
Requires the output to be formatted in general scientific notation
+ * as described below. The localization
+ * algorithm is applied.
+ *
+ *
After rounding for the precision, the formatting of the resulting
+ * magnitude m depends on its value.
+ *
+ *
If m is greater than or equal to 10-4 but less
+ * than 10precision then it is represented in decimal format.
+ *
+ *
If m is less than 10-4 or greater than or equal to
+ * 10precision, then it is represented in computerized scientific notation.
+ *
+ *
The total number of significant digits in m is equal to the
+ * precision. If the precision is not specified, then the default value is
+ * 6. If the precision is 0, then it is taken to be
+ * 1.
+ *
+ *
If the '#' flag is given then an {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
The result is a string that represents the sign and magnitude
+ * (absolute value) of the argument. The formatting of the sign is
+ * described in the localization
+ * algorithm. The formatting of the magnitude m depends upon its
+ * value.
+ *
+ *
If m NaN or infinite, the literal strings "NaN" or
+ * "Infinity", respectively, will be output. These values are not
+ * localized.
+ *
+ *
The magnitude is formatted as the integer part of m, with no
+ * leading zeroes, followed by the decimal separator followed by one or
+ * more decimal digits representing the fractional part of m.
+ *
+ *
The number of digits in the result for the fractional part of
+ * m or a is equal to the precision. If the precision is not
+ * specified then the default value is 6. If the precision is less
+ * than the number of digits which would appear after the decimal point in
+ * the string returned by {@link Float#toString(float)} or {@link
+ * Double#toString(double)} respectively, then the value will be rounded
+ * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * algorithm}. Otherwise, zeros may be appended to reach the precision.
+ * For a canonical representation of the value,use {@link
+ * Float#toString(float)} or {@link Double#toString(double)} as
+ * appropriate.
+ *
+ *
'a'
+ *
'\u0061'
+ *
Requires the output to be formatted in hexadecimal exponential
+ * form. No localization is applied.
+ *
+ *
The result is a string that represents the sign and magnitude
+ * (absolute value) of the argument x.
+ *
+ *
If x is negative or a negative-zero value then the result
+ * will begin with '-' ('\u002d').
+ *
+ *
If x is positive or a positive-zero value and the
+ * '+' flag is given then the result will begin with '+'
+ * ('\u002b').
+ *
+ *
The formatting of the magnitude m depends upon its value.
+ *
+ *
+ *
+ *
If the value is NaN or infinite, the literal strings "NaN" or
+ * "Infinity", respectively, will be output.
+ *
+ *
If m is zero then it is represented by the string
+ * "0x0.0p0".
+ *
+ *
If m is a double value with a normalized
+ * representation then substrings are used to represent the significand and
+ * exponent fields. The significand is represented by the characters
+ * "0x1." followed by the hexadecimal representation of the rest
+ * of the significand as a fraction. The exponent is represented by
+ * 'p' ('\u0070') followed by a decimal string of the
+ * unbiased exponent as if produced by invoking {@link
+ * Integer#toString(int) Integer.toString} on the exponent value.
+ *
+ *
If m is a double value with a subnormal
+ * representation then the significand is represented by the characters
+ * '0x0.' followed by the hexadecimal representation of the rest
+ * of the significand as a fraction. The exponent is represented by
+ * 'p-1022'. Note that there must be at least one nonzero digit
+ * in a subnormal significand.
+ *
+ *
+ *
+ *
If the '(' or ',' flags are given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'A'
+ *
'\u0041'
+ *
The upper-case variant of 'a'. The entire string
+ * representing the number will be converted to upper case including the
+ * 'x' ('\u0078') and 'p'
+ * ('\u0070' and all hexadecimal digits 'a' -
+ * 'f' ('\u0061' - '\u0066').
+ *
+ *
+ *
+ *
All flags defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ *
If the '#' flag is given, then the decimal separator will
+ * always be present.
+ *
+ *
If no flags are given the default formatting
+ * is as follows:
+ *
+ *
+ *
+ *
The output is right-justified within the width
+ *
+ *
Negative numbers begin with a '-'
+ *
+ *
Positive numbers and positive zero do not include a sign or extra
+ * leading space
+ *
+ *
No grouping separators are included
+ *
+ *
The decimal separator will only appear if a digit follows it
+ *
+ *
+ *
+ *
The width is the minimum number of characters
+ * to be written to the output. This includes any signs, digits, grouping
+ * separators, decimal separators, exponential symbol, radix indicator,
+ * parentheses, and strings representing infinity and NaN as applicable. If
+ * the length of the converted value is less than the width then the output
+ * will be padded by spaces ('\u0020') until the total number of
+ * characters equals width. The padding is on the left by default. If the
+ * '-' flag is given then the padding will be on the right. If width
+ * is not specified then there is no minimum.
+ *
+ *
If the conversion is 'e',
+ * 'E' or 'f', then the precision is the number of digits
+ * after the decimal separator. If the precision is not specified, then it is
+ * assumed to be 6.
+ *
+ *
If the conversion is 'g' or 'G', then the precision is
+ * the total number of significant digits in the resulting magnitude after
+ * rounding. If the precision is not specified, then the default value is
+ * 6. If the precision is 0, then it is taken to be
+ * 1.
+ *
+ *
If the conversion is 'a' or 'A', then the precision
+ * is the number of hexadecimal digits after the decimal separator. If the
+ * precision is not provided, then all of the digits as returned by {@link
+ * Double#toHexString(double)} will be output.
+ *
+ *
The formatting of the magnitude m depends upon its value.
+ *
+ *
If m is positive-zero or negative-zero, then the exponent
+ * will be "+00".
+ *
+ *
Otherwise, the result is a string that represents the sign and
+ * magnitude (absolute value) of the argument. The formatting of the sign
+ * is described in the localization
+ * algorithm. The formatting of the magnitude m depends upon its
+ * value.
+ *
+ *
Let n be the unique integer such that 10n
+ * <= m < 10n+1; then let a be the
+ * mathematically exact quotient of m and 10n so
+ * that 1 <= a < 10. The magnitude is then represented as the
+ * integer part of a, as a single decimal digit, followed by the
+ * decimal separator followed by decimal digits representing the fractional
+ * part of a, followed by the exponent symbol 'e'
+ * ('\u0065'), followed by the sign of the exponent, followed
+ * by a representation of n as a decimal integer, as produced by the
+ * method {@link Long#toString(long, int)}, and zero-padded to include at
+ * least two digits.
+ *
+ *
The number of digits in the result for the fractional part of
+ * m or a is equal to the precision. If the precision is not
+ * specified then the default value is 6. If the precision is
+ * less than the number of digits which would appear after the decimal
+ * point in the string returned by {@link Float#toString(float)} or {@link
+ * Double#toString(double)} respectively, then the value will be rounded
+ * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * algorithm}. Otherwise, zeros may be appended to reach the precision.
+ * For a canonical representation of the value, use {@link
+ * BigDecimal#toString()}.
+ *
+ *
If the ',' flag is given, then an {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
'E'
+ *
'\u0045'
+ *
The upper-case variant of 'e'. The exponent symbol
+ * will be 'E' ('\u0045').
+ *
+ *
'g'
+ *
'\u0067'
+ *
Requires the output to be formatted in general scientific notation
+ * as described below. The localization
+ * algorithm is applied.
+ *
+ *
After rounding for the precision, the formatting of the resulting
+ * magnitude m depends on its value.
+ *
+ *
If m is greater than or equal to 10-4 but less
+ * than 10precision then it is represented in decimal format.
+ *
+ *
If m is less than 10-4 or greater than or equal to
+ * 10precision, then it is represented in computerized scientific notation.
+ *
+ *
The total number of significant digits in m is equal to the
+ * precision. If the precision is not specified, then the default value is
+ * 6. If the precision is 0, then it is taken to be
+ * 1.
+ *
+ *
If the '#' flag is given then an {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
The result is a string that represents the sign and magnitude
+ * (absolute value) of the argument. The formatting of the sign is
+ * described in the localization
+ * algorithm. The formatting of the magnitude m depends upon its
+ * value.
+ *
+ *
The magnitude is formatted as the integer part of m, with no
+ * leading zeroes, followed by the decimal separator followed by one or
+ * more decimal digits representing the fractional part of m.
+ *
+ *
The number of digits in the result for the fractional part of
+ * m or a is equal to the precision. If the precision is not
+ * specified then the default value is 6. If the precision is
+ * less than the number of digits which would appear after the decimal
+ * point in the string returned by {@link Float#toString(float)} or {@link
+ * Double#toString(double)} respectively, then the value will be rounded
+ * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * algorithm}. Otherwise, zeros may be appended to reach the precision.
+ * For a canonical representation of the value, use {@link
+ * BigDecimal#toString()}.
+ *
+ *
+ *
+ *
All flags defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ *
If the '#' flag is given, then the decimal separator will
+ * always be present.
+ *
+ *
The default behavior when no flags are
+ * given is the same as for Float and Double.
+ *
+ *
The specification of width and precision is the same as defined for Float and
+ * Double.
+ *
+ *
This conversion may be applied to long, {@link Long}, {@link
+ * Calendar}, and {@link Date}.
+ *
+ *
+ *
+ *
't'
+ *
'\u0074'
+ *
Prefix for date and time conversion characters.
+ *
'T'
+ *
'\u0054'
+ *
The upper-case variant of 't'.
+ *
+ *
+ *
+ *
The following date and time conversion character suffixes are defined
+ * for the 't' and 'T' conversions. The types are similar to
+ * but not completely identical to those defined by GNU date and
+ * POSIX strftime(3c). Additional conversion types are provided to
+ * access Java-specific functionality (e.g. 'L' for milliseconds
+ * within the second).
+ *
+ *
The following conversion characters are used for formatting times:
+ *
+ *
+ *
+ *
'H'
+ *
'\u0048'
+ *
Hour of the day for the 24-hour clock, formatted as two digits with
+ * a leading zero as necessary i.e. 00 - 23. 00
+ * corresponds to midnight.
+ *
+ *
'I'
+ *
'\u0049'
+ *
Hour for the 12-hour clock, formatted as two digits with a leading
+ * zero as necessary, i.e. 01 - 12. 01 corresponds to
+ * one o'clock (either morning or afternoon).
+ *
+ *
'k'
+ *
'\u006b'
+ *
Hour of the day for the 24-hour clock, i.e. 0 - 23.
+ * 0 corresponds to midnight.
+ *
+ *
'l'
+ *
'\u006c'
+ *
Hour for the 12-hour clock, i.e. 1 - 12. 1
+ * corresponds to one o'clock (either morning or afternoon).
+ *
+ *
'M'
+ *
'\u004d'
+ *
Minute within the hour formatted as two digits with a leading zero
+ * as necessary, i.e. 00 - 59.
+ *
+ *
'S'
+ *
'\u0053'
+ *
Seconds within the minute, formatted as two digits with a leading
+ * zero as necessary, i.e. 00 - 60 ("60" is a special
+ * value required to support leap seconds).
+ *
+ *
'L'
+ *
'\u004c'
+ *
Millisecond within the second formatted as three digits with
+ * leading zeros as necessary, i.e. 000 - 999.
+ *
+ *
'N'
+ *
'\u004e'
+ *
Nanosecond within the second, formatted as nine digits with leading
+ * zeros as necessary, i.e. 000000000 - 999999999. The precision
+ * of this value is limited by the resolution of the underlying operating
+ * system or hardware.
+ *
+ *
'p'
+ *
'\u0070'
+ *
Locale-specific {@linkplain
+ * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ * in lower case, e.g."am" or "pm". Use of the
+ * conversion prefix 'T' forces this output to upper case. (Note
+ * that 'p' produces lower-case output. This is different from
+ * GNU date and POSIX strftime(3c) which produce
+ * upper-case output.)
+ *
+ *
'z'
+ *
'\u007a'
+ *
RFC 822
+ * style numeric time zone offset from GMT, e.g. -0800.
+ *
+ *
'Z'
+ *
'\u005a'
+ *
A string representing the abbreviation for the time zone.
+ *
+ *
's'
+ *
'\u0073'
+ *
Seconds since the beginning of the epoch starting at 1 January 1970
+ * 00:00:00 UTC, i.e. Long.MIN_VALUE/1000 to
+ * Long.MAX_VALUE/1000.
+ *
+ *
'Q'
+ *
'\u004f'
+ *
Milliseconds since the beginning of the epoch starting at 1 January
+ * 1970 00:00:00 UTC, i.e. Long.MIN_VALUE to
+ * Long.MAX_VALUE. The precision of this value is limited by
+ * the resolution of the underlying operating system or hardware.
+ *
+ *
+ *
+ *
The following conversion characters are used for formatting dates:
+ *
+ *
+ *
+ *
'B'
+ *
'\u0042'
+ *
Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ * full month name}, e.g. "January", "February".
+ *
+ *
Locale-specific full name of the {@linkplain
+ * java.text.DateFormatSymbols#getWeekdays day of the week},
+ * e.g. "Sunday", "Monday"
+ *
+ *
'a'
+ *
'\u0061'
+ *
Locale-specific short name of the {@linkplain
+ * java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ * e.g. "Sun", "Mon"
+ *
+ *
'C'
+ *
'\u0043'
+ *
Four-digit year divided by 100, formatted as two digits
+ * with leading zero as necessary, i.e. 00 - 99
+ *
+ *
'Y'
+ *
'\u0059'
Year, formatted to at least
+ * four digits with leading zeros as necessary, e.g. 0092 equals
+ * 92 CE for the Gregorian calendar.
+ *
+ *
'y'
+ *
'\u0079'
+ *
Last two digits of the year, formatted with leading zeros as
+ * necessary, i.e. 00 - 99.
+ *
+ *
'j'
+ *
'\u006a'
+ *
Day of year, formatted as three digits with leading zeros as
+ * necessary, e.g. 001 - 366 for the Gregorian calendar.
+ * 001 corresponds to the first day of the year.
+ *
+ *
'm'
+ *
'\u006d'
+ *
Month, formatted as two digits with leading zeros as necessary,
+ * i.e. 01 - 13, where "01" is the first month of the
+ * year and ("13" is a special value required to support lunar
+ * calendars).
+ *
+ *
'd'
+ *
'\u0064'
+ *
Day of month, formatted as two digits with leading zeros as
+ * necessary, i.e. 01 - 31, where "01" is the first day
+ * of the month.
+ *
+ *
'e'
+ *
'\u0065'
+ *
Day of month, formatted as two digits, i.e. 1 - 31 where
+ * "1" is the first day of the month.
+ *
+ *
+ *
+ *
The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ *
+ *
+ *
'R'
+ *
'\u0052'
+ *
Time formatted for the 24-hour clock as "%tH:%tM"
+ *
+ *
'T'
+ *
'\u0054'
+ *
Time formatted for the 24-hour clock as "%tH:%tM:%tS".
+ *
+ *
'r'
+ *
'\u0072'
+ *
Time formatted for the 12-hour clock as "%tI:%tM:%tS
+ * %Tp". The location of the morning or afternoon marker
+ * ('%Tp') may be locale-dependent.
+ *
+ *
'D'
+ *
'\u0044'
+ *
Date formatted as "%tm/%td/%ty".
+ *
+ *
'F'
+ *
'\u0046'
+ *
ISO 8601
+ * complete date formatted as "%tY-%tm-%td".
+ *
+ *
'c'
+ *
'\u0063'
+ *
Date and time formatted as "%ta %tb %td %tT %tZ %tY",
+ * e.g. "Sun Jul 20 16:17:00 EDT 1969".
+ *
+ *
+ *
+ *
The '-' flag defined for General
+ * conversions applies. If the '#' flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
The width is the minimum number of characters to
+ * be written to the output. If the length of the converted value is less than
+ * the width then the output will be padded by spaces
+ * ('\u0020') until the total number of characters equals width.
+ * The padding is on the left by default. If the '-' flag is given
+ * then the padding will be on the right. If width is not specified then there
+ * is no minimum.
+ *
+ *
The precision is not applicable. If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ *
The conversion does not correspond to any argument.
+ *
+ *
+ *
+ *
'%'
+ *
The result is a literal '%' ('\u0025')
+ *
+ *
The width is the minimum number of characters to
+ * be written to the output including the '%'. If the length of the
+ * converted value is less than the width then the output will be
+ * padded by spaces ('\u0020') until the total number of
+ * characters equals width. The padding is on the left. If width is not
+ * specified then just the '%' is output.
+ *
+ *
The '-' flag defined for General
+ * conversions applies. If any other flags are provided, then a
+ * {@link FormatFlagsConversionMismatchException} will be thrown.
+ *
+ *
The precision is not applicable. If the precision is specified an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ *
The conversion does not correspond to any argument.
+ *
+ *
+ *
+ *
'n'
+ *
the platform-specific line separator as returned by {@link
+ * System#getProperty System.getProperty("line.separator")}.
+ *
+ *
+ *
+ *
Flags, width, and precision are not applicable. If any are provided an
+ * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException},
+ * and {@link IllegalFormatPrecisionException}, respectively will be thrown.
+ *
+ *
Format specifiers can reference arguments in three ways:
+ *
+ *
+ *
+ *
Explicit indexing is used when the format specifier contains an
+ * argument index. The argument index is a decimal integer indicating the
+ * position of the argument in the argument list. The first argument is
+ * referenced by "1$", the second by "2$", etc. An argument
+ * may be referenced more than once.
+ *
+ *
For example:
+ *
+ *
+ * formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s",
+ * "a", "b", "c", "d")
+ * // -> "d c b a d c b a"
+ *
+ *
+ *
Relative indexing is used when the format specifier contains a
+ * '<' ('\u003c') flag which causes the argument for
+ * the previous format specifier to be re-used. If there is no previous
+ * argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ *
+ * formatter.format("%s %s %<s %<s", "a", "b", "c", "d")
+ * // -> "a b b b"
+ * // "c" and "d" are ignored because they are not referenced
+ *
+ *
+ *
Ordinary indexing is used when the format specifier contains
+ * neither an argument index nor a '<' flag. Each format specifier
+ * which uses ordinary indexing is assigned a sequential implicit index into
+ * argument list which is independent of the indices used by explicit or
+ * relative indexing.
+ *
+ *
+ * formatter.format("%s %s %s %s", "a", "b", "c", "d")
+ * // -> "a b c d"
+ *
+ *
+ *
+ *
+ *
It is possible to have a format string which uses all forms of indexing,
+ * for example:
+ *
+ *
+ * formatter.format("%2$s %s %<s %s", "a", "b", "c", "d")
+ * // -> "b a a b"
+ * // "c" and "d" are ignored because they are not referenced
+ *
+ *
+ *
The maximum number of arguments is limited by the maximum dimension of a
+ * Java array as defined by the Java Virtual Machine
+ * Specification. If the argument index is does not correspond to an
+ * available argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ *
If there are more arguments than format specifiers, the extra arguments
+ * are ignored.
+ *
+ *
Unless otherwise specified, passing a null argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @author Iris Clark
+ * @since 1.5
+ */
+public final class Formatter implements Closeable, Flushable {
+ private Appendable a;
+ private Locale l;
+
+ private IOException lastException;
+
+ private char zero = '0';
+ private static double scaleUp;
+
+ // 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
+ // + 3 (max # exp digits) + 4 (error) = 30
+ private static final int MAX_FD_CHARS = 30;
+
+ // Initialize internal data.
+ private void init(Appendable a, Locale l) {
+ this.a = a;
+ this.l = l;
+ setZero();
+ }
+
+ /**
+ * Constructs a new formatter.
+ *
+ *
The destination of the formatted output is a {@link StringBuilder}
+ * which may be retrieved by invoking {@link #out out()} and whose
+ * current content may be converted into a string by invoking {@link
+ * #toString toString()}. The locale used is the {@linkplain
+ * Locale#getDefault() default locale} for this instance of the Java
+ * virtual machine.
+ */
+ public Formatter() {
+ init(new StringBuilder(), Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified destination.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault() default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param a
+ * Destination for the formatted output. If a is
+ * null then a {@link StringBuilder} will be created.
+ */
+ public Formatter(Appendable a) {
+ if (a == null)
+ a = new StringBuilder();
+ init(a, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified locale.
+ *
+ *
The destination of the formatted output is a {@link StringBuilder}
+ * which may be retrieved by invoking {@link #out out()} and whose current
+ * content may be converted into a string by invoking {@link #toString
+ * toString()}.
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If l is null then no localization
+ * is applied.
+ */
+ public Formatter(Locale l) {
+ init(new StringBuilder(), l);
+ }
+
+ /**
+ * Constructs a new formatter with the specified destination and locale.
+ *
+ * @param a
+ * Destination for the formatted output. If a is
+ * null then a {@link StringBuilder} will be created.
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If l is null then no localization
+ * is applied.
+ */
+ public Formatter(Appendable a, Locale l) {
+ if (a == null)
+ a = new StringBuilder();
+ init(a, l);
+ }
+
+ /**
+ * Constructs a new formatter with the specified file name.
+ *
+ *
The charset used is the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault() default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this
+ * formatter. If the file exists then it will be truncated to
+ * zero size; otherwise, a new file will be created. The output
+ * will be written to the file and is buffered.
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @throws FileNotFoundException
+ * If the given file name does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ */
+ public Formatter(String fileName) throws FileNotFoundException {
+ init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
+ Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified file name and charset.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this
+ * formatter. If the file exists then it will be truncated to
+ * zero size; otherwise, a new file will be created. The output
+ * will be written to the file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given file name does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(String fileName, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(fileName, csn, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified file name, charset, and
+ * locale.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this
+ * formatter. If the file exists then it will be truncated to
+ * zero size; otherwise, a new file will be created. The output
+ * will be written to the file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If l is null then no localization
+ * is applied.
+ *
+ * @throws FileNotFoundException
+ * If the given file name does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(String fileName, String csn, Locale l)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), csn)),
+ l);
+ }
+
+ /**
+ * Constructs a new formatter with the specified file.
+ *
+ *
The charset used is the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault() default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param file
+ * The file to use as the destination of this formatter. If the
+ * file exists then it will be truncated to zero size; otherwise,
+ * a new file will be created. The output will be written to the
+ * file and is buffered.
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())} denies
+ * write access to the file
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ */
+ public Formatter(File file) throws FileNotFoundException {
+ init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
+ Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified file and charset.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param file
+ * The file to use as the destination of this formatter. If the
+ * file exists then it will be truncated to zero size; otherwise,
+ * a new file will be created. The output will be written to the
+ * file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())} denies
+ * write access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(File file, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(file, csn, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified file, charset, and
+ * locale.
+ *
+ * @param file
+ * The file to use as the destination of this formatter. If the
+ * file exists then it will be truncated to zero size; otherwise,
+ * a new file will be created. The output will be written to the
+ * file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If l is null then no localization
+ * is applied.
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())} denies
+ * write access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(File file, String csn, Locale l)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)),
+ l);
+ }
+
+ /**
+ * Constructs a new formatter with the specified print stream.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault() default
+ * locale} for this instance of the Java virtual machine.
+ *
+ *
Characters are written to the given {@link java.io.PrintStream
+ * PrintStream} object and are therefore encoded using that object's
+ * charset.
+ *
+ * @param ps
+ * The stream to use as the destination of this formatter.
+ */
+ public Formatter(PrintStream ps) {
+ if (ps == null)
+ throw new NullPointerException();
+ init((Appendable)ps, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified output stream.
+ *
+ *
The charset used is the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault() default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param os
+ * The output stream to use as the destination of this formatter.
+ * The output will be buffered.
+ */
+ public Formatter(OutputStream os) {
+ init(new BufferedWriter(new OutputStreamWriter(os)),
+ Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified output stream and
+ * charset.
+ *
+ *
The locale used is the {@linkplain Locale#getDefault default
+ * locale} for this instance of the Java virtual machine.
+ *
+ * @param os
+ * The output stream to use as the destination of this formatter.
+ * The output will be buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(OutputStream os, String csn)
+ throws UnsupportedEncodingException
+ {
+ this(os, csn, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new formatter with the specified output stream, charset,
+ * and locale.
+ *
+ * @param os
+ * The output stream to use as the destination of this formatter.
+ * The output will be buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If l is null then no localization
+ * is applied.
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public Formatter(OutputStream os, String csn, Locale l)
+ throws UnsupportedEncodingException
+ {
+ init(new BufferedWriter(new OutputStreamWriter(os, csn)), l);
+ }
+
+ private void setZero() {
+ if ((l != null) && !l.equals(Locale.US)) {
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+ zero = dfs.getZeroDigit();
+ }
+ }
+
+ /**
+ * Returns the locale set by the construction of this formatter.
+ *
+ *
The {@link #format(java.util.Locale,String,Object...) format} method
+ * for this object which has a locale argument does not change this value.
+ *
+ * @return null if no localization is applied, otherwise a
+ * locale
+ *
+ * @throws FormatterClosedException
+ * If this formatter has been closed by invoking its {@link
+ * #close()} method
+ */
+ public Locale locale() {
+ ensureOpen();
+ return l;
+ }
+
+ /**
+ * Returns the destination for the output.
+ *
+ * @return The destination for the output
+ *
+ * @throws FormatterClosedException
+ * If this formatter has been closed by invoking its {@link
+ * #close()} method
+ */
+ public Appendable out() {
+ ensureOpen();
+ return a;
+ }
+
+ /**
+ * Returns the result of invoking toString() on the destination
+ * for the output. For example, the following code formats text into a
+ * {@link StringBuilder} then retrieves the resultant string:
+ *
+ *
+ * Formatter f = new Formatter();
+ * f.format("Last reboot at %tc", lastRebootDate);
+ * String s = f.toString();
+ * // -> s == "Last reboot at Sat Jan 01 00:00:00 PST 2000"
+ *
+ *
+ *
An invocation of this method behaves in exactly the same way as the
+ * invocation
+ *
+ *
+ * out().toString()
+ *
+ *
Depending on the specification of toString for the {@link
+ * Appendable}, the returned string may or may not contain the characters
+ * written to the destination. For instance, buffers typically return
+ * their contents in toString(), but streams cannot since the
+ * data is discarded.
+ *
+ * @return The result of invoking toString() on the destination
+ * for the output
+ *
+ * @throws FormatterClosedException
+ * If this formatter has been closed by invoking its {@link
+ * #close()} method
+ */
+ public String toString() {
+ ensureOpen();
+ return a.toString();
+ }
+
+ /**
+ * Flushes this formatter. If the destination implements the {@link
+ * java.io.Flushable} interface, its flush method will be invoked.
+ *
+ *
Flushing a formatter writes any buffered output in the destination
+ * to the underlying stream.
+ *
+ * @throws FormatterClosedException
+ * If this formatter has been closed by invoking its {@link
+ * #close()} method
+ */
+ public void flush() {
+ ensureOpen();
+ if (a instanceof Flushable) {
+ try {
+ ((Flushable)a).flush();
+ } catch (IOException ioe) {
+ lastException = ioe;
+ }
+ }
+ }
+
+ /**
+ * Closes this formatter. If the destination implements the {@link
+ * java.io.Closeable} interface, its close method will be invoked.
+ *
+ *
Closing a formatter allows it to release resources it may be holding
+ * (such as open files). If the formatter is already closed, then invoking
+ * this method has no effect.
+ *
+ *
Attempting to invoke any methods except {@link #ioException()} in
+ * this formatter after it has been closed will result in a {@link
+ * FormatterClosedException}.
+ */
+ public void close() {
+ if (a == null)
+ return;
+ try {
+ if (a instanceof Closeable)
+ ((Closeable)a).close();
+ } catch (IOException ioe) {
+ lastException = ioe;
+ } finally {
+ a = null;
+ }
+ }
+
+ private void ensureOpen() {
+ if (a == null)
+ throw new FormatterClosedException();
+ }
+
+ /**
+ * Returns the IOException last thrown by this formatter's {@link
+ * Appendable}.
+ *
+ *