dbf-exporter fix broken symbol: replace unsupported character on whitespace (см. также параметр export-dbf-service.common.encoding)
This commit is contained in:
parent
eceb681861
commit
2760ddc7d3
3 changed files with 155 additions and 1 deletions
|
|
@ -0,0 +1,47 @@
|
|||
package ru.spcex.clearing.dbf.exporter.logic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* При перекодировании текста в кодировку, которая не поддерживает символы - они заменяются на знак "?".
|
||||
* Надо чтобы они заменялись не на "?", а на пробел.
|
||||
*/
|
||||
public class CharsetFilter {
|
||||
final Charset charset;
|
||||
|
||||
public CharsetFilter(Charset dbfCharset) {
|
||||
this.charset = dbfCharset;
|
||||
Objects.requireNonNull(charset);
|
||||
}
|
||||
|
||||
public String filterUnsupportedChars(String text) {
|
||||
if (text == null || text.isEmpty())
|
||||
return text;
|
||||
CharBuffer textBuf = CharBuffer.wrap(text);
|
||||
ByteBuffer bBuffer = charset.encode(textBuf);
|
||||
CharBuffer cBuffer = charset.decode(bBuffer);
|
||||
if (cBuffer.equals(textBuf)) {
|
||||
return text;
|
||||
} else {
|
||||
char[] arr = text.toCharArray();
|
||||
if (arr.length != cBuffer.length())
|
||||
return text; // never
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (cBuffer.get(i) != arr[i]) {
|
||||
arr[i] = ' ';
|
||||
}
|
||||
}
|
||||
return String.valueOf(arr);
|
||||
}
|
||||
|
||||
/* Можно было так:
|
||||
sun.nio.cs.ThreadLocalCoders.encoderFor(charset)
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE)
|
||||
.encode(textBuf);
|
||||
но для этого надо добавить '--add-exports java.base/sun.nio.cs=ALL-UNNAMED' в опции*/
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
|
|||
import ru.spcex.clearing.dbf.exporter.config.SFTPConfig;
|
||||
import ru.spcex.clearing.dbf.exporter.config.settings.ExportDBFServiceSettings;
|
||||
import ru.spcex.clearing.dbf.exporter.exceptions.ConfigException;
|
||||
import ru.spcex.clearing.dbf.exporter.logic.CharsetFilter;
|
||||
import ru.spcex.clearing.dbf.exporter.logic.data.ResultContainer;
|
||||
import ru.spcex.clearing.dbf.exporter.logic.data.enums.StageResult;
|
||||
import ru.spcex.clearing.dbf.exporter.logic.data.enums.Table;
|
||||
|
|
@ -68,6 +69,7 @@ public class ExportFromHazelcast extends Stage implements InitializingBean {
|
|||
String currency = null;
|
||||
String path = null;
|
||||
try (DBFWriter dbfWriter = new DBFWriter(dbfFile, dbfCharset)) {
|
||||
CharsetFilter charsetFilter = new CharsetFilter(dbfWriter.getCharset());
|
||||
Collection<? extends SpcexObjectBase> tableRows;
|
||||
if (resultContainer.getGroupId() != null) {
|
||||
Map<String, Long> queryParams = Map.of("generationId", resultContainer.getGroupId());
|
||||
|
|
@ -95,7 +97,13 @@ public class ExportFromHazelcast extends Stage implements InitializingBean {
|
|||
currency = currentConverter.getCurrency(value);
|
||||
dbfWriter.setFields(currentConverter.getDBFHeaders());
|
||||
}
|
||||
dbfWriter.addRecord(currentConverter.toObjectArray(value));
|
||||
Object[] rawRow = currentConverter.toObjectArray(value);
|
||||
for (int i = 0; i < rawRow.length; i++) {
|
||||
if (rawRow[i] instanceof String rowText) {
|
||||
rawRow[i] = charsetFilter.filterUnsupportedChars(rowText);
|
||||
}
|
||||
}
|
||||
dbfWriter.addRecord(rawRow);
|
||||
}
|
||||
if (CurrencyCode.isRub(currency))
|
||||
path = settings.getStore().getOutPayValDir().get(ruCurrency);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package ru.spcex.clearing.dbf.exporter.logic;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CharsetFilterTest {
|
||||
|
||||
@Test
|
||||
void filterUnsupportedChars_utf8() {
|
||||
CharsetFilter filter = new CharsetFilter(Charset.forName("utf-8"));
|
||||
assertEquals(null, filter.filterUnsupportedChars(null));
|
||||
assertEquals("", filter.filterUnsupportedChars(""));
|
||||
String empty = "";
|
||||
assertSame(empty, filter.filterUnsupportedChars(empty));
|
||||
assertEquals("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));", filter.filterUnsupportedChars("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));"));
|
||||
assertEquals("Test обычные АБВЭЮЯёЁ ABCXYZ", filter.filterUnsupportedChars("Test обычные АБВЭЮЯёЁ ABCXYZ"));
|
||||
assertEquals("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-=", filter.filterUnsupportedChars("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-="));
|
||||
assertEquals(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю.",
|
||||
filter.filterUnsupportedChars(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю."));
|
||||
assertEquals("Акционерный «Абсо\nлют» ", filter.filterUnsupportedChars("Акционерный «Абсо\nлют» "));
|
||||
assertEquals("К«а»вычки '\" и п\160р о б\u2060е л\u8199ы. И иные символы: …„‘\n" +
|
||||
"2018 \t’\n2019 \t“\n201C \t”\n201D \t•\n2022 \t–\n2013 \t—\n2014 \t\t™\n2122 \tљ\n459 \t›",
|
||||
filter.filterUnsupportedChars("К«а»вычки '\" и п\160р о б\u2060е л\u8199ы. И иные символы: …„‘\n" +
|
||||
"2018 \t’\n2019 \t“\n201C \t”\n201D \t•\n2022 \t–\n2013 \t—\n2014 \t\t™\n2122 \tљ\n459 \t›"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterUnsupportedChars_windows1251() {
|
||||
CharsetFilter filter = new CharsetFilter(Charset.forName("windows-1251"));
|
||||
assertEquals(null, filter.filterUnsupportedChars(null));
|
||||
assertEquals("", filter.filterUnsupportedChars(""));
|
||||
String empty = "";
|
||||
assertSame(empty, filter.filterUnsupportedChars(empty));
|
||||
assertEquals("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));", filter.filterUnsupportedChars("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));"));
|
||||
assertEquals("Test обычные АБВЭЮЯёЁ ABCXYZ", filter.filterUnsupportedChars("Test обычные АБВЭЮЯёЁ ABCXYZ"));
|
||||
assertEquals("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-=", filter.filterUnsupportedChars("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-="));
|
||||
assertEquals(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю.",
|
||||
filter.filterUnsupportedChars(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю."));
|
||||
assertEquals("Акционерный «Абсо\nлют» ", filter.filterUnsupportedChars("Акционерный «Абсо\nлют» "));
|
||||
assertEquals("К«а»вычки '\" и пpр о б е л ы. И иные символы: …„‘\n" +
|
||||
"2018 \t’\n2019 \t“\n201C \t”\n201D \t•\n2022 \t–\n2013 \t—\n2014 \t\t™\n2122 \tљ\n459 \t›",
|
||||
filter.filterUnsupportedChars("К«а»вычки '\" и п\160р о б\u2060е л\u8199ы. И иные символы: …„‘\n" +
|
||||
"2018 \t’\n2019 \t“\n201C \t”\n201D \t•\n2022 \t–\n2013 \t—\n2014 \t\t™\n2122 \tљ\n459 \t›"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterUnsupportedChars_cp866() {
|
||||
CharsetFilter filter = new CharsetFilter(Charset.forName("cp866"));
|
||||
assertEquals(null, filter.filterUnsupportedChars(null));
|
||||
assertEquals("", filter.filterUnsupportedChars(""));
|
||||
String empty = "";
|
||||
assertSame(empty, filter.filterUnsupportedChars(empty));
|
||||
assertEquals("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));", filter.filterUnsupportedChars("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));"));
|
||||
assertEquals("Test обычные АБВЭЮЯёЁ ABCXYZ", filter.filterUnsupportedChars("Test обычные АБВЭЮЯёЁ ABCXYZ"));
|
||||
assertEquals("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-=", filter.filterUnsupportedChars("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-="));
|
||||
assertEquals(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю.",
|
||||
filter.filterUnsupportedChars(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю."));
|
||||
assertEquals("Акционерный Абсо\nлют ", filter.filterUnsupportedChars("Акционерный «Абсо\nлют» "));
|
||||
assertEquals("К а вычки '\" и пpр о б е л ы. И иные символы: \n" +
|
||||
"2018 \t \n2019 \t \n201C \t \n201D \t \n2022 \t \n2013 \t \n2014 \t\t \n2122 \t \n459 \t ",
|
||||
filter.filterUnsupportedChars("К«а»вычки '\" и п\160р о б\u2060е л\u8199ы. И иные символы: …„‘\n" +
|
||||
"2018 \t’\n2019 \t“\n201C \t”\n201D \t•\n2022 \t–\n2013 \t—\n2014 \t\t™\n2122 \tљ\n459 \t›"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void canCorrectEncode() throws UnsupportedEncodingException {
|
||||
String sample = " 0123456789/*-+:;,. .,~!@#$%^&*()_+` '\"\\(…„‘) К«а»в’ы“ч™кљи п\160р о б\u2060е л\u8199ы qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю.ёЁ";
|
||||
sample = "Test aaabbbccc АААБББВВВЯЯЯяяяЁ: " + sample + sample + sample;
|
||||
for (String charset : new String[]{"utf-8", "windows-1251", "cp866"}) {
|
||||
CharsetFilter filter = new CharsetFilter(Charset.forName(charset));
|
||||
String toEnc = filter.filterUnsupportedChars(sample);
|
||||
byte[] b = toEnc.getBytes(charset);
|
||||
String returned = new String(b, charset);
|
||||
assertEquals(toEnc, returned, charset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Кодировка не используется, но она применяется по умолчанию в библиотеке DBFStandardCharsets
|
||||
*/
|
||||
@Test
|
||||
void filterUnsupportedChars_ISO_8859_1() {
|
||||
CharsetFilter filter = new CharsetFilter(Charset.forName("ISO_8859_1")); //DBFStandardCharsets.ISO_8859_1
|
||||
assertEquals(null, filter.filterUnsupportedChars(null));
|
||||
assertEquals("", filter.filterUnsupportedChars(""));
|
||||
assertEquals("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));", filter.filterUnsupportedChars("assertEquals(\"\", filter.filterUnsupportedChars(\"\"));"));
|
||||
assertEquals("Test ABCXYZ", filter.filterUnsupportedChars("Test обычные АБВЭЮЯёЁ ABCXYZ"));
|
||||
assertEquals("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-=", filter.filterUnsupportedChars("/*-+:;'\\/.,~!@#$%^&*()_+`1234567890-="));
|
||||
assertEquals(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM .",
|
||||
filter.filterUnsupportedChars(" 0123456789/*-+:;,.'\"\\()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю."));
|
||||
assertEquals(" « \n » ", filter.filterUnsupportedChars("Акционерный «Абсо\nлют» "));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue