在使用地图期间编码字符串
Encoding string during using maps
我觉得我的字符串(带有变音符号)在我的 class 中采用不同的编码,在 hashmap 中采用不同的编码(对于其他地图实例也是“工作”)字符串在我的 class,我尝试将其用作地图中的键,并在其中放置一些值,当我尝试通过键获取该值时,它不起作用。有趣的事情 - 在 intellij 评估期间按预期工作。
一些细节:
IntelliJ IDEA 2019.3.1 (Community Edition)
Build #IC-193.5662.53,
built on December 18,
2019 Runtime version: 11.0.5+10-b520.17 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o Windows 10 10.0 GC:
ParNew, ConcurrentMarkSweep Memory: 1986M Cores: 4 Registry:
Non-Bundled Plugins:
used SDK Java 1.8.0_231
为了检查案例是否可重复,我创建了这个 junit:
@Test
public void test() {
Map<String, String> map = new TreeMap<>();
map.put("język", "polski");
String res = map.get("język");
System.out.println(res);
}
在输入 hashmap 时,单词“język”被转换为“j?zyk”,但在从 map 中获取它时,它也被转换为“j?zyk”,所以一切看起来都很好。但在我的生产代码中,它更复杂。我使用以下代码从字符串列表创建了地图:
private Map<String, String> getBookDetails(HtmlElement from) {
HtmlElement bookDetails = BOOK_DETAILS.getFirst(from);
return Arrays.stream(bookDetails.asText().split(BOOK_DETAILS_SEPARATOR))
.collect(MappingErrors.collector());
}
bookDetails.asXml:
<div class="collapse d-xs-none" id="book-details">
<dl>
<dt>
Tytuł oryginału:
</dt>
<dd>
Wat?
</dd>
<dt>
Data wydania:
</dt>
<dd>
2016-05-16
</dd>
<dt data-toggle="tooltip" title="Data pierwszego wydania polskiego">
Data 1. wyd. pol.:
</dt>
<dd>
2016-05-16
</dd>
<dt>
Liczba stron:
</dt>
<dd>
20
</dd>
<dt>
Język:
</dt>
<dd>
polski
</dd>
<dt>
ISBN:
</dt>
<dd>
9788374206600
</dd>
<dt>
Tłumacz:
</dt>
<dd>
<a href="https://lubimyczytac.pl/tlumacz/10593/ryszard-turczyn">
Ryszard Turczyn
</a>
</dd>
<dt class="d-lg-none">
Wydawnictwo:
</dt>
<dd class="d-lg-none">
<a href="https://lubimyczytac.pl/wydawnictwo/13832/wydawnictwo-adamada/ksiazki">
Wydawnictwo Adamada
</a>
</dd>
</dl>
</div>
缺少变量
private String BOOK_DETAILS_SEPARATOR = "\r\n";
static final DefinedHtmlElement BOOK_DETAILS =
new DefinedHtmlElement("div", "id", "book-details");
DefinedHtmlElement 内部 class:
static class DefinedHtmlElement {
String elementName;
String attributeName;
String attributeValue;
DefinedHtmlElement (String elementName, String attributeName, String attributeValue) {
this.attributeName = attributeName;
this.elementName = elementName;
this.attributeValue = attributeValue;
}
public String getAttributeName() {
return attributeName;
}
public String getAttributeValue() {
return attributeValue;
}
public String getElementName() {
return elementName;
}
public HtmlElement getFirst(HtmlElement element) {
return element
.getElementsByAttribute(elementName, attributeName, attributeValue)
.stream().findFirst().orElse(null);
}
}
收藏家:
private static final class MappingErrors {
private static int counter = 1;
private Map<String, String> map = new TreeMap<>();
private String first;
private String second;
public void accept(String str) {
first = second;
second = str;
if (first != null && counter % 2 == 0) {
map.put(first.trim(), second.trim());
}
counter++;
}
public MappingErrors combine(MappingErrors other) {
throw new UnsupportedOperationException("Parallel Stream not supported");
}
public Map<String, String> finish() {
return map;
}
public static Collector<String, ?, Map<String, String>> collector() {
return Collector.of(MappingErrors::new, MappingErrors::accept, MappingErrors::combine,
MappingErrors::finish);
}
}
有趣的是,在将 key/value 放入地图时,它并没有转换为问号版本,而是按原样写入。当我尝试通过键获取值时,键字符串被转换,找不到任何匹配的键,并且代码不工作。我尝试使用单词“Język:”作为关键字,得到“JÄ>trade mark sign
我不知道在哪里可以找到根本原因。我检查所有文件是否具有相同的编码(utf-8 和 windows 1252 在这种情况下以相同的方式工作)所有项目都设置了相同的编码,没有输入文件,仅从网页抓取并获取字符串通过 com.gargoylesoftware.htmlunit.html.HtmlElement 如果它很重要。有谁知道在哪里可以找到根本原因?编码是正确的线索,还是完全不同的东西?当然我可以创建 walkaround 以将所有变音符号替换为正常字符,但我想了解发生了什么
更新:
我发现来自 gargoylesoftware 的数据不同。这不是一种填充地图的方式,它没有连接到地图(实际上地图是第一个可见的地方)。我修改了一点代码:
private Map<String, String> getBookDetails(HtmlElement from) {
HtmlElement bookDetails = BOOK_DETAILS.getFirst(from);
String[] split = bookDetails.asText().split(BOOK_DETAILS_SEPARATOR);
Map<String, String> mapa = new HashMap<>();
for (int i=0;i<split.length-1;i+=2) {
mapa.put(split[i].trim(), split[i+1].trim());
if (split[i].trim().compareTo("Język:") == 0) {
System.out.println("test");
}
}
mapa.put("Język:","TEST");
return mapa;
}
if 中的条件永远不会为真。它仍然只在评估期间为真,但永远不会达到与 println 一致。 Object 地图看起来像这样:
"Data 1. wyd. pol.:" -> "2016-05-16"
"Liczba stron:" -> "20"
"Data wydania:" -> "2016-05-16"
"Tłumacz:" -> "Ryszard Turczyn"
"Język:" -> "TEST"
"Tytuł oryginału:" -> "Wat?"
"Język:" -> "polski"
"Wydawnictwo:" -> "Wydawnictwo Adamada"
"ISBN:" -> "9788374206600"
所以手动添加的条目以某种方式更改为“TM”版本。但没关系,因为在从这张地图获取价值的过程中发生了同样的变化,所以价值是正确的。但是,为什么手动输入的字符串与 gargoylesoftware 中的字符串不同?
我找到了! intellij, windows 和网页的编码关系很复杂。 HtmlElement 中的数据有 utf8,String 有 utf16,windows 有他自己的,而 intellij 有所有这些的某种组合。我正在尝试使用 String 构造函数并找到正确的组合。
new String(labelFromHtmlElement.getBytes("UTF-8"), "windows-1252");
使用变音符号进行编程可能会很复杂:)
我觉得我的字符串(带有变音符号)在我的 class 中采用不同的编码,在 hashmap 中采用不同的编码(对于其他地图实例也是“工作”)字符串在我的 class,我尝试将其用作地图中的键,并在其中放置一些值,当我尝试通过键获取该值时,它不起作用。有趣的事情 - 在 intellij 评估期间按预期工作。 一些细节:
IntelliJ IDEA 2019.3.1 (Community Edition) Build #IC-193.5662.53, built on December 18, 2019 Runtime version: 11.0.5+10-b520.17 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o Windows 10 10.0 GC: ParNew, ConcurrentMarkSweep Memory: 1986M Cores: 4 Registry: Non-Bundled Plugins:
used SDK Java 1.8.0_231
为了检查案例是否可重复,我创建了这个 junit:
@Test
public void test() {
Map<String, String> map = new TreeMap<>();
map.put("język", "polski");
String res = map.get("język");
System.out.println(res);
}
在输入 hashmap 时,单词“język”被转换为“j?zyk”,但在从 map 中获取它时,它也被转换为“j?zyk”,所以一切看起来都很好。但在我的生产代码中,它更复杂。我使用以下代码从字符串列表创建了地图:
private Map<String, String> getBookDetails(HtmlElement from) {
HtmlElement bookDetails = BOOK_DETAILS.getFirst(from);
return Arrays.stream(bookDetails.asText().split(BOOK_DETAILS_SEPARATOR))
.collect(MappingErrors.collector());
}
bookDetails.asXml:
<div class="collapse d-xs-none" id="book-details">
<dl>
<dt>
Tytuł oryginału:
</dt>
<dd>
Wat?
</dd>
<dt>
Data wydania:
</dt>
<dd>
2016-05-16
</dd>
<dt data-toggle="tooltip" title="Data pierwszego wydania polskiego">
Data 1. wyd. pol.:
</dt>
<dd>
2016-05-16
</dd>
<dt>
Liczba stron:
</dt>
<dd>
20
</dd>
<dt>
Język:
</dt>
<dd>
polski
</dd>
<dt>
ISBN:
</dt>
<dd>
9788374206600
</dd>
<dt>
Tłumacz:
</dt>
<dd>
<a href="https://lubimyczytac.pl/tlumacz/10593/ryszard-turczyn">
Ryszard Turczyn
</a>
</dd>
<dt class="d-lg-none">
Wydawnictwo:
</dt>
<dd class="d-lg-none">
<a href="https://lubimyczytac.pl/wydawnictwo/13832/wydawnictwo-adamada/ksiazki">
Wydawnictwo Adamada
</a>
</dd>
</dl>
</div>
缺少变量
private String BOOK_DETAILS_SEPARATOR = "\r\n";
static final DefinedHtmlElement BOOK_DETAILS =
new DefinedHtmlElement("div", "id", "book-details");
DefinedHtmlElement 内部 class:
static class DefinedHtmlElement {
String elementName;
String attributeName;
String attributeValue;
DefinedHtmlElement (String elementName, String attributeName, String attributeValue) {
this.attributeName = attributeName;
this.elementName = elementName;
this.attributeValue = attributeValue;
}
public String getAttributeName() {
return attributeName;
}
public String getAttributeValue() {
return attributeValue;
}
public String getElementName() {
return elementName;
}
public HtmlElement getFirst(HtmlElement element) {
return element
.getElementsByAttribute(elementName, attributeName, attributeValue)
.stream().findFirst().orElse(null);
}
}
收藏家:
private static final class MappingErrors {
private static int counter = 1;
private Map<String, String> map = new TreeMap<>();
private String first;
private String second;
public void accept(String str) {
first = second;
second = str;
if (first != null && counter % 2 == 0) {
map.put(first.trim(), second.trim());
}
counter++;
}
public MappingErrors combine(MappingErrors other) {
throw new UnsupportedOperationException("Parallel Stream not supported");
}
public Map<String, String> finish() {
return map;
}
public static Collector<String, ?, Map<String, String>> collector() {
return Collector.of(MappingErrors::new, MappingErrors::accept, MappingErrors::combine,
MappingErrors::finish);
}
}
有趣的是,在将 key/value 放入地图时,它并没有转换为问号版本,而是按原样写入。当我尝试通过键获取值时,键字符串被转换,找不到任何匹配的键,并且代码不工作。我尝试使用单词“Język:”作为关键字,得到“JÄ>trade mark sign 我不知道在哪里可以找到根本原因。我检查所有文件是否具有相同的编码(utf-8 和 windows 1252 在这种情况下以相同的方式工作)所有项目都设置了相同的编码,没有输入文件,仅从网页抓取并获取字符串通过 com.gargoylesoftware.htmlunit.html.HtmlElement 如果它很重要。有谁知道在哪里可以找到根本原因?编码是正确的线索,还是完全不同的东西?当然我可以创建 walkaround 以将所有变音符号替换为正常字符,但我想了解发生了什么 更新:
我发现来自 gargoylesoftware 的数据不同。这不是一种填充地图的方式,它没有连接到地图(实际上地图是第一个可见的地方)。我修改了一点代码: if 中的条件永远不会为真。它仍然只在评估期间为真,但永远不会达到与 println 一致。 Object 地图看起来像这样: 所以手动添加的条目以某种方式更改为“TM”版本。但没关系,因为在从这张地图获取价值的过程中发生了同样的变化,所以价值是正确的。但是,为什么手动输入的字符串与 gargoylesoftware 中的字符串不同?private Map<String, String> getBookDetails(HtmlElement from) {
HtmlElement bookDetails = BOOK_DETAILS.getFirst(from);
String[] split = bookDetails.asText().split(BOOK_DETAILS_SEPARATOR);
Map<String, String> mapa = new HashMap<>();
for (int i=0;i<split.length-1;i+=2) {
mapa.put(split[i].trim(), split[i+1].trim());
if (split[i].trim().compareTo("Język:") == 0) {
System.out.println("test");
}
}
mapa.put("Język:","TEST");
return mapa;
}
"Data 1. wyd. pol.:" -> "2016-05-16"
"Liczba stron:" -> "20"
"Data wydania:" -> "2016-05-16"
"Tłumacz:" -> "Ryszard Turczyn"
"Język:" -> "TEST"
"Tytuł oryginału:" -> "Wat?"
"Język:" -> "polski"
"Wydawnictwo:" -> "Wydawnictwo Adamada"
"ISBN:" -> "9788374206600"
我找到了! intellij, windows 和网页的编码关系很复杂。 HtmlElement 中的数据有 utf8,String 有 utf16,windows 有他自己的,而 intellij 有所有这些的某种组合。我正在尝试使用 String 构造函数并找到正确的组合。
new String(labelFromHtmlElement.getBytes("UTF-8"), "windows-1252");
使用变音符号进行编程可能会很复杂:)