我正在尝试解析CSV文件,最好使用weka.core.converters.CSVLoader。但是,我拥有的文件不是有效的UTF-8文件。它主要是一个UTF-8文件,但是某些字段值使用不同的编码,因此没有一种编码方式可以使整个文件有效,但是无论如何我都需要对其进行解析。除了使用像Weka这样的Java库之外,我主要在Scala中工作。我什至无法读取scala.io中的文件。资料来源:例如
Source. fromFile(filename)("UTF-8"). foreach(print);
抛出:
java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:277) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:337) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:153) at java.io.BufferedReader.read(BufferedReader.java:174) at scala.io.BufferedSource$$anonfun$iter$1$$anonfun$apply$mcI$sp$1.apply$mcI$sp(BufferedSource.scala:38) at scala.io.Codec.wrap(Codec.scala:64) at scala.io.BufferedSource$$anonfun$iter$1.apply(BufferedSource.scala:38) at scala.io.BufferedSource$$anonfun$iter$1.apply(BufferedSource.scala:38) at scala.collection.Iterator$$anon$14.next(Iterator.scala:150) at scala.collection.Iterator$$anon$25.hasNext(Iterator.scala:562) at scala.collection.Iterator$$anon$19.hasNext(Iterator.scala:400) at scala.io.Source.hasNext(Source.scala:238) at scala.collection.Iterator$class.foreach(Iterator.scala:772) at scala.io.Source.foreach(Source.scala:181)
我非常乐意丢掉所有无效字符或用一些虚拟字符替换它们。我将有很多这样的文本以各种方式处理,并且可能需要将数据传递给各种第三方库。理想的解决方案是某种全局设置,该设置将导致所有低级Java库忽略文本中的无效字节,以便我可以对此数据调用第三方库而无需进行修改。
解:
import java.nio.charset.CodingErrorAction import scala.io.Codec implicit val codec = Codec("UTF-8") codec.onMalformedInput(CodingErrorAction.REPLACE) codec.onUnmappableCharacter(CodingErrorAction.REPLACE) val src = Source. fromFile(filename). foreach(print)
感谢+ Esailija为我指出正确的方向。这导致我转向如何检测非法的UTF-8字节序列以将其替换为java inputstream? 它提供了核心的Java解决方案。在Scala中,我可以通过将编码解码器隐式设置为默认行为。我认为可以通过将隐式编解码器定义放在包对象中,使它成为整个包的默认行为。
这是我设法用java做到的方式:
FileInputStream input; String result = null; try { input = new FileInputStream(new File("invalid.txt")); CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); decoder.onMalformedInput(CodingErrorAction.IGNORE); InputStreamReader reader = new InputStreamReader(input, decoder); BufferedReader bufferedReader = new BufferedReader( reader ); StringBuilder sb = new StringBuilder(); String line = bufferedReader.readLine(); while( line != null ) { sb.append( line ); line = bufferedReader.readLine(); } bufferedReader.close(); result = sb.toString(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch( IOException e ) { e.printStackTrace(); } System.out.println(result);
使用字节创建无效文件:
0x68, 0x80, 0x65, 0x6C, 0x6C, 0xC3, 0xB6, 0xFE, 0x20, 0x77, 0xC3, 0xB6, 0x9C, 0x72, 0x6C, 0x64, 0x94
hellö wörld在UTF-8中,其中混入了4个无效字节。
hellö wörld
有了.REPLACE你看到正在使用的标准Unicode替换字符:
.REPLACE
//"h�ellö� wö�rld�"
使用.IGNORE,您会看到无效字节被忽略:
.IGNORE
//"hellö wörld"
不指定.onMalformedInput,您得到
.onMalformedInput
java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(Unknown Source) at sun.nio.cs.StreamDecoder.implRead(Unknown Source) at sun.nio.cs.StreamDecoder.read(Unknown Source) at java.io.InputStreamReader.read(Unknown Source) at java.io.BufferedReader.fill(Unknown Source) at java.io.BufferedReader.readLine(Unknown Source) at java.io.BufferedReader.readLine(Unknown Source)