一种指定模式字符串的方法,可以驱动任意对象的解析和格式化?

时间:2009-06-25 20:18:38

标签: java parsing formatting

我正在使用Java 5为内部企业使用构建通用数据转换工具。各个部门对坐标信息(纬度/经度)使用不同的格式,并且他们希望以自己的格式查看数据。例如,白宫以DMS格式的坐标是

38°53'55.133“N,77°02'15.691”W

但也可以表达为:

385355.133 / -0770215.691

我希望将每个系统所需的模式表示为字符串,然后使用这些模式来解析输入系统中的实例数据,并在格式化字符串以供输出系统使用时使用该模式。

因此它与日期/时间格式问题没有什么不同,JDK提供了java.text.SimpleDateFormat,它允许您在各种日期/时间模式之间进行转换,这些模式由字符串定义,例如“YYYY-MM-DD”或“MM / DD / YY”。

我的问题是,我是否必须从头开始构建这个CoordinateFormat的东西,还是有一个很好的通用工具或明确的方法我可以用来指导我这项工作?

6 个答案:

答案 0 :(得分:1)

如果我读得正确,你就是在谈论Interpreter模式所解决的问题,而是两个方向都有。

有一些简单的方法可以获得漂亮的通用接口,因此您可以运行其余的东西。我对此的建议如下:

public interface Interpreter<OutputType> {
public void setCode(String coding);
public OutputType decode(String formattedData);
public String encode(OutputType rawData); }

然而,具体实施存在一些障碍。对于您的日期示例,您可能需要处理“9/9/09”,“9 SEP 09”,“2009年9月9日”。日期的第一个“类型”是直截了当的 - 数字和设置分隔符号,但其他两个中的任何一个都非常讨厌。老实说,做一些完全通用的东西(可能已经固定)可能是不合理的,所以我推荐以下内容。

我会在两个级别上攻击它,第一个是使用正则表达式和格式字符串非常简单:将数据字符串扼杀到将成为原始数据的内容中。你会为第一个提供“D * / M * / YY”(或“M * / D *”),第二个提供“D * MMM YY”,“Mm + D * e *,YYYY”最后,您在数据中定义了一些保留符号(D,M,Y,明显的解释)和所有数据类型(*可能的多个字符,+“完整”输出,e定义的无关字符) - 这些符号显然是特定于您的应用程序。然后你的正则表达式会填充字符串,将与每个保留字符相关的所有内容提供给各个数据字段,并将装饰部分(逗号等)保存在某些格式化字符串中。

这个第一级都可以是相当通用的 - 每种数据类型(例如,日期,坐标,地址)都有保留符号(不与任何格式化字符重叠),并且所有数据类型都有一些共享符号。也许Interpreter接口也有public List<Character> reservedSymbols()public void splitCode(List<String> splitcodes)方法,或者可能是保证字段,这样你就可以将分隔符作为外部类并传入结果。

第二级不太容易,因为它处于不能通用的部分。基于保留符号的格式,各个字段需要知道如何呈现自己。在日期示例中,MM会告诉月份打印为(01,02,... 12),M *为(1,2,... 12),MMM为(JAN,FEB,... DEC) ,嗯如(1月,2月,12月)等。如果你的公司有点一致或者没有远离标准的东西表示,那么手工编码这些都不应该太糟糕(和实际上,每种数据类型中可能都有智能方法来减少复制代码。但我不认为将所有这些东西归为一类是切合实际的 - 我的意思是,实际上代表的东西可以表示为数字或字符(如月)或可以从部分数据推断出的整个数据(例如,从年份开始的世纪)或者如何从数据中获取截断的表示(例如,截断年份是最后两位数,最正常的数字截断为两个前导数字)可能需要手写这些情况,尽管我想我可以想象你的应用案例的权衡可能是值得的。日期是一个非常棘手的例子,但我当然可以看到其他类型的数据同样棘手的事情。

要点:

- 这是一个简单的通用面孔,可以解决您的问题,因此您的应用程序的其余部分可以围绕它进行编码。

- 通过使用通用保留符号,然后为每种数据类型保留符号,这是一个相当简单和通用的第一遍解析;确保它们不会与格式化中出现的符号发生冲突

- 个别数据位的最终编码阶段有点单调乏味

答案 1 :(得分:0)

查看JScience,特别是this class

答案 2 :(得分:0)

#1。我认为定义一个共同的内部格式会有所帮助。您可以根据输出的要求将输入格式转换为内部格式和任意数量的格式。   #2。 RegEx将是我选择实现转换器。

答案 3 :(得分:0)

一种解决方案是定义一个规范系统,从中可以导出输入正则表达式(或其他)和输出格式字符串。如果你有一个允许命名捕获组的正则表达式系统和一个允许非顺序参数的格式化系统,这可能就像重新编码一个到另一个的转义和索引一样简单。我不知道Java,所以我会把细节留给读者。

答案 4 :(得分:0)

对我而言,看起来您正在为您的解决方案寻找更大的框架。

我看到的主要问题是你正在寻找一个银弹来淘汰任何类型的数据。但是,随着java的发展,最一致的方式是包装正则表达式。每种对象类型都需要一个定义可接受格式的字符串列表。所以日期可能有很多,坐标有2等等。

这些字符串可以是正则表达式(痛苦但一致且可接受),或者您可以编写自己的转换库来执行以下操作:

转换器c =新转换器();
FormatString format = new FormatString(“ddmmss.sss”);
format.AddRegexEquivalent( “d”, “\\ d”);
format.AddRegexEquivalent( “M”, “\\ d”);
format.AddRegexEquivalent( “S”, “\\ d”);
c.AddFormatString(格式);

if(c.ConvertString(“385355.133”))
{
System.out.println(c.GetData(“d”));
System.out.println(c.GetData(“m”));
System.out.println(c.GetData(“s”));
}


输出:
38个
53个
55.133

这很难,但我认为这更像是你在寻找的东西。转换器必须将给定的字母转换为正则表达式。 (作为一个开始,你可以只是批量替换),然后连接每个字母的所有值。我会从GetData返回一个String,然后从那里使用Parse ***,更容易处理。

答案 5 :(得分:0)

wicket中的TextTemplate类通过插入带有键值对映射的“模板”字符串来生成字符串。您可以使用输出模式字符串作为基础,使用变量从地图中为每个值(经度,分钟,等等)进行插值。这不会进行双向转换,但您可以查看它并查看它是否对您有所帮助。

http://wicketstuff.org/wicket13doc/org/apache/wicket/util/template/TextTemplate.html

这是来自他们的svn:

的来源

http://svn.apache.org/repos/asf/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/template/TextTemplate.java