如何将Java中的字符从扩展ASCII或Unicode转换为它们的7位ASCII等价物,包括诸如open之类的特殊字符(“
0x 93)并关闭(”
0x 94)引号转换为简单双引号("
0x 22)。或类似的破折号(–
0x 96)转换为连字符-减号(-
0x 2d).我已经发现Stack Overflow questions与此类似,但答案似乎只处理口音,忽略了特殊字符。
例如,我想将“Caffè – Peña”
转换为"Caffe - Pena"
。
然而当我使用java.text.Normalizer时:
String sample = "“Caffè – Peña”";
System.out.println(Normalizer.normalize(sample, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}", ""));
输出为
“Caffe – Pena”
为了阐明我的需求,我正在与一个使用EBCDIC编码的IBM i Db2数据库交互。例如,如果用户粘贴一个从Word或Outlook复制的字符串,类似于我指定的字符将被转换为SUB(在EBCDIC中为0x 3F,在ASCII中为0x 1A)。这会导致许多不必要的麻烦。我正在寻找一种方法来净化字符串,以便尽可能少地丢失信息。
3条答案
按热度按时间vktxenjb1#
您可以按照另一位评论者的建议,使用String.replace()替换引号字符,并且随着时间的推移,问题字符的列表可能会越来越多。
您也可以使用更通用的函数来替换或忽略任何无法编码的字符。例如:
例如,你可以把
_encoding
称为“IBM-037”。但是,如果您的目标是尽可能少地丢失信息,则应评估数据是否可以以UTF-8格式存储(CCSID 1208)。这可以很好地处理智能引号和其他“特殊字符”。根据您的数据库和应用程序结构,这样的更改可能实现起来非常小,或者它可能非常大并且有风险!但是实现无损翻译的唯一方法是使用unicode风格,UTF-8是最明智的。
qc6wkl3g2#
有些评论者说你的问题是“主观的”(不是指基于观点的问题,而是指每个人的具体要求与其他人的要求略有不同),或者定义不明确,或者根本不可能解决......这些评论在技术上是正确的。
但是你在寻找一些你可以做的实际的事情来改善这种情况,这也是完全有效的。
在实现难度与结果准确性之间取得平衡的最佳方法是将你已经发现的内容与来自不太负面的评论者的建议结合起来:
上面的 * 可能 * 涵盖了“所有”未来的情况,这取决于数据的来源。或者足够接近所有你可以实现它并完成它的情况。如果你想增加一些健壮性,并将在一段时间内保持这个过程,那么你也可以提出一个列表,列出你想在净化后的结果中允许的所有字符。然后设置某种异常或日志记录机制,使您(或您的继任者)能够在出现新的未处理情况时找到它们,然后可以使用这些情况来改进Map的自定义部分。
50few1ms3#
经过一些挖掘,我能够找到基于this answer的解决方案,使用org.apache.lucene.analysis.ASCIIFoldingFilter
我能找到的所有示例都使用了foldToASCII方法的静态版本,如this project中所示:
然而,该静态方法有一个注解,它说
此API仅供内部使用,在下一版本中可能会以不兼容的方式进行更改。
因此,经过一些反复试验,我得出了这个避免使用静态方法的版本:
与我提供的答案here类似。
这正是我要找的,并将字符翻译为它们的ASCII 7位等效版本。
然而,通过进一步的研究,我发现,由于我主要处理Windows-1252编码,并且由于jt 400处理ASCII EBCDIC的方式<->,(CCSID 37)转换,如果将ASCII字符串转换为EBCDIC,然后再转换回ACSII,则丢失的字符只有
0x80
到0x9f
。因此,受lucene's foldToASCII处理方式的启发,我把下面的方法放在一起,只处理这些情况:由于我的真实的问题是Windows-1252到Latin-1(ISO-8859-1)的转换,因此这里有一个supporting material,它显示了上述方法中使用的Windows-1252到Unicode的转换,以最终获得Latin-1编码。