java.text.MessageFormat格式化字符串时的小技巧

时间:2023-02-22 10:22:54

java.text.MessageFormat类
MessageFormat提供一种语言无关的方式来组装消息,它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式,在其中你可以用占位符来表示变化的部分:

import java.text.MessageFormat;
import java.util.Date; public class MessageFormatTest {
public static void main(String[] args) {
Object[] arguments = {
7,
new Date(System.currentTimeMillis()),
"a disturbance in the Force"
};
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
arguments);
System.out.println(result);
//output:
// At 14:08:27 on 2017-7-7, there was a disturbance in the Force on planet 7.
}
}

占位符的格式为{ ArgumentIndex , FormatType , FormatStyle },详细说明可以参考MessageFormat的API说明文档。这里我们定义了两个占位符,其中的数字对应于传入的参数数组中的索引,{0}占位符被第一个参数替换,{1}占位符被第二个参数替换,依此类推。
最多可以设置10个占位符,而且每个占位符可以重复出现多次,而且格式可以不同,比如{1,date}和{1,time},{1,number,#.##}。而通过将这些模式定义放到不同的资源文件中,就能够根据不同的locale设置,得到不同的模式定义,并用参数动态替换占位符。
步骤:
1、找出可变的部分,并据此定义模式,将模式放入不同的资源文件中。
2、创建MessageFormat对象,并设置其locale属性。
MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);
3、从资源包中得到模式定义,以及设置参数。
messages = ResourceBundle.getBundle(
"i18n.resource.MessagesBundle",currentLocale);
Object[] arguments= {new Long(3), "MyDisk"};;
4、利用模式定义和参数进行格式化。
String result = MessageFormat.format(messages.getString(key), arguments);

http://blog.csdn.net/turkeyzhou/article/details/4487917

注意:
参数为Number类型Date类型时,会被格式化。数字会转换成科学计数法,譬如 123456,会format成 123,456
java.text.MessageFormat#subformat

    /**
* Internal routine used by format. If <code>characterIterators</code> is
* non-null, AttributedCharacterIterator will be created from the
* subformats as necessary. If <code>characterIterators</code> is null
* and <code>fp</code> is non-null and identifies
* <code>Field.MESSAGE_ARGUMENT</code>, the location of
* the first replaced argument will be set in it.
*
* @exception IllegalArgumentException if an argument in the
* <code>arguments</code> array is not of the type
* expected by the format element(s) that use it.
*/
private StringBuffer subformat(Object[] arguments, StringBuffer result,
FieldPosition fp, List<AttributedCharacterIterator> characterIterators) {
// note: this implementation assumes a fast substring & index.
// if this is not true, would be better to append chars one by one.
int lastOffset = 0;
int last = result.length();
for (int i = 0; i <= maxOffset; ++i) {
result.append(pattern.substring(lastOffset, offsets[i]));
lastOffset = offsets[i];
int argumentNumber = argumentNumbers[i];
if (arguments == null || argumentNumber >= arguments.length) {
result.append('{').append(argumentNumber).append('}');
continue;
}
// int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
if (false) { // if (argRecursion == 3){
// prevent loop!!!
result.append('\uFFFD');
} else {
Object obj = arguments[argumentNumber];
String arg = null;
Format subFormatter = null;
if (obj == null) {
arg = "null";
} else if (formats[i] != null) {
subFormatter = formats[i];
if (subFormatter instanceof ChoiceFormat) {
arg = formats[i].format(obj);
if (arg.indexOf('{') >= 0) {
subFormatter = new MessageFormat(arg, locale);
obj = arguments;
arg = null;
}
}
} else if (obj instanceof Number) {
// format number if can
subFormatter = NumberFormat.getInstance(locale);
} else if (obj instanceof Date) {
// format a Date if can
subFormatter = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.SHORT, locale);//fix
} else if (obj instanceof String) {
arg = (String) obj; } else {
arg = obj.toString();
if (arg == null) arg = "null";
} // At this point we are in two states, either subFormatter
// is non-null indicating we should format obj using it,
// or arg is non-null and we should use it as the value. if (characterIterators != null) {
// If characterIterators is non-null, it indicates we need
// to get the CharacterIterator from the child formatter.
if (last != result.length()) {
characterIterators.add(
createAttributedCharacterIterator(result.substring
(last)));
last = result.length();
}
if (subFormatter != null) {
AttributedCharacterIterator subIterator =
subFormatter.formatToCharacterIterator(obj); append(result, subIterator);
if (last != result.length()) {
characterIterators.add(
createAttributedCharacterIterator(
subIterator, Field.ARGUMENT,
Integer.valueOf(argumentNumber)));
last = result.length();
}
arg = null;
}
if (arg != null && arg.length() > 0) {
result.append(arg);
characterIterators.add(
createAttributedCharacterIterator(
arg, Field.ARGUMENT,
Integer.valueOf(argumentNumber)));
last = result.length();
}
}
else {
if (subFormatter != null) {
arg = subFormatter.format(obj);
}
last = result.length();
result.append(arg);
if (i == 0 && fp != null && Field.ARGUMENT.equals(
fp.getFieldAttribute())) {
fp.setBeginIndex(last);
fp.setEndIndex(result.length());
}
last = result.length();
}
}
}
result.append(pattern.substring(lastOffset, pattern.length()));
if (characterIterators != null && last != result.length()) {
characterIterators.add(createAttributedCharacterIterator(
result.substring(last)));
}
return result;
}

Java里从来少不了字符串拼接的活,Java程序员也肯定用到过StringBuffer,StringBuilder,以及被编译器优化掉的+=。但这些都和下文要谈的无关。

直接使用"+"拼接比较多的字符串,变量一多,可读性就下降,出错的几率就增加,并且难以维护。
需要拼接的变量比较多时,可以使用MessageFormat.format。
示例:

String[] tdArr={...};
String result=MessageFormat.format("<tr bgcolor='#cef'><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>", tdArr);

这段代码将把数组tdArr中的四个元素分别插入到{0},{1},{2},{3}的位置。

你看看,是不是这样形式和内容有效的分开了。容易想象,当元素增多时,这种方式优势很明显。
一件事有很多手段来达成,知道那种手段更好,是你经验的体现和专业化的特征。

使用下标来决定拼接的位置,第一个参数的下标为0,pattern中下标的位置是不要求是顺序的

    public static void main(String[] args) {
String longitude = "1.0";
String latitude = "2.0";
String result = "result";
String geoCode = "geoCode"; String format1 = MessageFormat.format("longitude:{0},latitude:{1}, body:{2},reGeoCode:{3}", longitude, latitude, result, geoCode);
System.out.println(format1);
String format2 = MessageFormat.format("longitude:{3},latitude:{2}, body:{1},reGeoCode:{0}", longitude, latitude, result, geoCode);
System.out.println(format2); String format3 = MessageFormat.format("longitude:{2},latitude:{3}, body:{0},reGeoCode:{1}", longitude, latitude, result, geoCode);
System.out.println(format3); }

输出:

longitude:1.0,latitude:2.0, body:result,reGeoCode:geoCode
longitude:geoCode,latitude:result, body:2.0,reGeoCode:1.0
longitude:result,latitude:geoCode, body:1.0,reGeoCode:2.0

java.text.MessageFormat格式化字符串时的小技巧

    public static void main(String[] args) throws InterruptedException {
MessageFormat form = new MessageFormat(
"{2,date,yyyy-MM-dd HH:mm:ss.SSS} The disk \"{1}\" contains {0,number,#.##} file(s).{3}");
int fileCount = 1273273237;
String diskName = "MyDisk";
Object[] testArgs = {new Long(fileCount), diskName, new Date(),new Date()};
System.out.println(form.format(testArgs));
}
执行结果:

2016-05-26 13:41:59.162 The disk "MyDisk" contains 1273273237 file(s).16-5-26 下午1:41

如果缺少ArgumentIndex 则会报错:

java.lang.IllegalArgumentException: can't parse argument number:
at java.text.MessageFormat.makeFormat(MessageFormat.java:1429)
at java.text.MessageFormat.applyPattern(MessageFormat.java:479)
at java.text.MessageFormat.<init>(MessageFormat.java:362)
at java.text.MessageFormat.format(MessageFormat.java:840)

java.text.MessageFormat格式化字符串时的小技巧的更多相关文章

  1. java&period;text&period;MessageFormat 专题

    java.text.MessageFormat类MessageFormat提供一种语言无关的方式来组装消息,它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分.你可以为MessageForma ...

  2. java中用MessageFormat格式化json字符串用占位符时出现的问题can&&num;39&semi;t parse argument number

    在MessageFormat.format方法中组装jason数据字符串:{code:"w1",des:"w2"},起止分别有左大括号和右大括号. 直接写的点位 ...

  3. 【java初探】——格式化字符串

    String 类的静态方法format()方法用于创建格式化字符串,format()方法有两种重载形式: format(String fromat,Object...args) 该方法使用指定的格式字 ...

  4. Java程序员阅读源码的小技巧,原来大牛都是这样读的,赶紧看看!

    今天介跟大家分享一下我平时阅读源码的几个小技巧,对于阅读java中间件如Spring.Dubbo等框架源码的同学有一定帮助. 本文基于Eclipse IDE,我们每天都使用的IDE其实提供了很多强大的 ...

  5. 【java编程】格式化字符串

    String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处.format()方法有两种重载形式. form ...

  6. Windows下程序打包发布时的小技巧

    一.背景 Windows下开发的应用程序在发布时,需要将其依赖的一些动态链接库一起打进安装包里面去.这个时候,快速确定这个程序到底依赖哪些动态链接库变得非常重要.很久以前写过一篇关于Qt程序安装包制作 ...

  7. Java web开发中页面跳转小技巧——跳转后新页面在新窗口打开

    最近学习Java web,在学习过程中想实现一个需求,就是在jsp页面跳转的时候,希望跳转后的新页面在新窗口中打开, 而不是覆盖原来的页面,这个需求使我困惑了好长时间,后来通过大海捞针似的在网上寻找方 ...

  8. vim字符串替换及小技巧

    vi/vim 中可以使用 :s 命令来替换字符串.以前只会使用一种格式来全文替换,今天发现该命令有很多种写法(vi 真是强大啊,还有很多需要学习),记录几种在此,方便以后查询. :s/vivian/s ...

  9. Windows下程序打包发布时的小技巧(使用Dependency Walker侦测不理想,改用VS自带的dumpbin则万无一失,还可查看dll导出的函数)

    Windows下开发的应用程序在发布时,需要将其依赖的一些动态链接库一起打进安装包里面去.这个时候,快速确定这个程序到底依赖哪些动态链接库变得非常重要.很久以前写过一篇关于Qt程序安装包制作的博客,里 ...

随机推荐

  1. The default for KeyValuePair

    if (getResult.Equals(new KeyValuePair<T,U>())) or this: if (getResult.Equals(default(KeyValueP ...

  2. Struts2&lpar;三&rpar;——数据在框架中的数据流转问题

    一款软件,无在乎对数据的处理.而B/S软件,一般都是用户通过浏览器客户端输入数据,传递到服务器,服务器进行相关处理,然后返回到指定的页面,进行相关显示,完成相关功能.这篇博客重点简述一下Struts2 ...

  3. 大湾区联动&colon;广州深圳助力东莞&period;NET俱乐部首次线下活动

    新年伊始,经过一个寒冬考验后的.NET社区热情不减,长沙.南京.合肥.东莞先后建立以微信为主要平台的线上.NET社区.并相继开始筹划和组织各地区的首次线下活动.东莞作为粤港澳大湾区的腹地,制造业基地, ...

  4. 骑士(树形dp)

    题意:给你一个基环树森林,每个点有一个权值,一条边上的两个节点不能同时选择.选取任意个节点,求最大权值和 对于每颗基环树:找环→断边→树形dp(没有上司的舞会) #include<iostrea ...

  5. Codeforces Round &num;425 &lpar;Div&period; 2&rpar;

    A 题意:给你n根棍子,两个人每次拿m根你,你先拿,如果该谁拿的时候棍子数<m,这人就输,对手就赢,问你第一个拿的人能赢吗 代码: #include<stdio.h>#define ...

  6. 面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

    前言 17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍. 根据我的面试经验 ...

  7. python 元类的简单解释

    本文转自博客:http://www.cnblogs.com/piperck/p/5840443.html 作者:piperck python 类和元类(metaclass)的理解和简单运用 (一) p ...

  8. 微软官方的Windowsphone社区

    微软官方的Windowsphone社区 http://answers.microsoft.com/zh-hans/winphone/forum/wp8?tab=Threads http://answe ...

  9. 一个简单的 openssl 示例

    ////生成一个私钥////$key=openssl_pkey_new();openssl_pkey_export($key,$out);//等于下面写入的内容////将私钥写入一个文件////ope ...

  10. idea 添加 VUE 的语法支持和开发

    <一>VUE的开发分两种,一种是直接在HTML文件中使用,一种是VUE文件的形式开发 1,首先我们先让 HTML 文件支持 VUE 的语法指令提示 2,File -> Setting ...