java - 将带有特殊字符的字符串转换为 JSONObject
问题描述
我的输入字符串为"{"notes_text": "someString"}"
. someString 可以包含 \ 或 "。我需要创建一个 JSONObject 来表示这个字符串。
如果它包含特殊字符,只需使用将字符串作为输入的构造函数将引发异常。
我已经尝试了几种方法来做到这一点
- 使用库来转义字符 - 例如,这将导致
"{\"notes_text\":\"\"\"}"
或"{\"notes_text\":\"\\\"}"
. 我需要将它们分别更改为"{\"notes_text\":\"\\\"\"}"
and"{\"notes_text\":\"\\\\\"}"
,否则它会在转换为 JSON 对象时再次抛出异常。在字符串中使用 replace 方法将转换输入字符串中的所有 \" - 不要转义输入字符串中的特殊字符并使用字符串替换方法将\转换为\和“到\”。但这将再次替换输入字符串中的所有双引号
我尝试使用正则表达式,但无法理解替换字符串str.replaceAll("\\\".*\\\".*\\\"", replacemntString)
解决方案
课程
这里有两个类可以解决损坏 json 的初始问题:
public class FixedJson {
private final String target;
private final Pattern pattern;
public FixedJson(String target) {
this(
target,
Pattern.compile("\"(.+?)\"[^\\w\"]")
);
}
public FixedJson(String target, Pattern pattern) {
this.target = target;
this.pattern = pattern;
}
public String value() {
return this.pattern.matcher(this.target).replaceAll(
matchResult -> {
StringBuilder sb = new StringBuilder();
sb.append(
matchResult.group(),
0,
matchResult.start(1) - matchResult.start(0)
);
sb.append(
new Escaped(
new Escaped(matchResult.group(1)).value()
).value()
);
sb.append(
matchResult.group().substring(
matchResult.group().length() - (matchResult.end(0) - matchResult.end(1))
)
);
return sb.toString();
}
);
}
}
public class Escaped {
private final String target;
private final Pattern pattern;
public Escaped(String target) {
this(
target,
Pattern.compile("[\\\\\"]")
);
}
public Escaped(String target, Pattern pattern) {
this.target = target;
this.pattern = pattern;
}
public String value() {
return this.pattern
.matcher(this.target)
.replaceAll("\\\\$0");
}
}
单元测试
我已经编写了单元测试来证明正确性:
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class FixedJsonTest {
@Test
public void normalValue() {
assertEquals(
"{\"notes_text\": \"someString\"}",
new FixedJson("{\"notes_text\": \"someString\"}").value()
);
}
@Test
public void valueWithOneDoubleQuotes() {
assertEquals(
"{\"notes_text\": \"\\\"\"}",
new FixedJson("{\"notes_text\": \"\"\"}").value()
);
}
@Test
public void valueWithOneDoubleQuotesAndAnotherValue() {
assertEquals(
"{\"notes_text\": \"\\\"\", \"hello\": \"world\"}",
new FixedJson("{\"notes_text\": \"\"\", \"hello\": \"world\"}").value()
);
}
@Test
public void valueWithTwoDoubleQuotes() {
assertEquals(
"{\"notes_text\": \"\\\"\\\"\"}",
new FixedJson("{\"notes_text\": \"\"\"\"}").value()
);
}
@Test
public void valueWithTwoDoubleQuotesAndAnotherValue() {
assertEquals(
"{\"notes_text\": \"\\\"\\\"\", \"hello\": \"world\"}",
new FixedJson("{\"notes_text\": \"\"\"\", \"hello\": \"world\"}").value()
);
}
@Test
public void valueWithOneSlash() {
assertEquals(
"{\"notes_text\": \"\\\\\"}",
new FixedJson("{\"notes_text\": \"\\\"}").value()
);
}
@Test
public void valueWithOneSlashAndAnotherValue() {
assertEquals(
"{\"notes_text\": \"\\\\\", \"hello\": \"world\"}",
new FixedJson("{\"notes_text\": \"\\\", \"hello\": \"world\"}").value()
);
}
@Test
public void valueWithTwoSlashes() {
assertEquals(
"{\"notes_text\": \"\\\\\\\\\"}",
new FixedJson("{\"notes_text\": \"\\\\\"}").value()
);
}
@Test
public void valueWithTwoSlashesAndAnotherValue() {
assertEquals(
"{\"notes_text\": \"\\\\\\\\\", \"hello\": \"world\"}",
new FixedJson("{\"notes_text\": \"\\\\\", \"hello\": \"world\"}").value()
);
}
}
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class EscapedTest {
@Test
public void doubleQuotesTest() {
assertEquals(
new Escaped("\"").value(),
"\\\""
);
assertEquals(
new Escaped("abc\"def").value(),
"abc\\\"def"
);
}
@Test
public void slashesTest() {
assertEquals(
new Escaped("\\").value(),
"\\\\"
);
assertEquals(
new Escaped("abc\\def").value(),
"abc\\\\def"
);
}
@Test
public void mixedTest() {
assertEquals(
new Escaped("\\\"").value(),
"\\\\\\\""
);
assertEquals(
new Escaped("abc\\\"def").value(),
"abc\\\\\\\"def"
);
}
}
完整的工作示例
import java.util.regex.Pattern;
public class FixedJsonExample {
public static void main(String[] args) {
String invalidJson = "{\"notes_text\":\"\"\"}";
final String fixedJson = new FixedJson(invalidJson).value();
System.out.println("fixedJson = " + fixedJson);
}
public static class FixedJson {
private final String target;
private final Pattern pattern;
public FixedJson(String target) {
this(
target,
Pattern.compile("\"(.+?)\"[^\\w\"]")
);
}
public FixedJson(String target, Pattern pattern) {
this.target = target;
this.pattern = pattern;
}
public String value() {
return this.pattern.matcher(this.target).replaceAll(
matchResult -> {
StringBuilder sb = new StringBuilder();
sb.append(
matchResult.group(),
0,
matchResult.start(1) - matchResult.start(0)
);
sb.append(
new Escaped(
new Escaped(matchResult.group(1)).value()
).value()
);
sb.append(
matchResult.group().substring(
matchResult.group().length() - (matchResult.end(0) - matchResult.end(1))
)
);
return sb.toString();
}
);
}
}
public static class Escaped {
private final String target;
private final Pattern pattern;
public Escaped(String target) {
this(
target,
Pattern.compile("[\\\\\"]")
);
}
public Escaped(String target, Pattern pattern) {
this.target = target;
this.pattern = pattern;
}
public String value() {
return this.pattern
.matcher(this.target)
.replaceAll("\\\\$0");
}
}
}
及其标准输出:
fixedJson = {"notes_text":"\""}
可以使用以下工具验证此 JSON:https ://jsonlint.com/
正则表达式解释
FixedJson
班级
第一类FixedJson
使用正则表达式来匹配 JSON 引理:双引号之间的所有内容(包括放错位置的双引号)。
有关更多详细信息,请参见此处的交互式示例:https ://regexr.com/54blf
Escaped
班级
第二类Escaped
使用正则表达式来匹配斜杠或双引号。这是他们逃跑的必要条件。
有关更多详细信息,请参见此处的交互式示例:https ://regexr.com/54bm1
推荐阅读
- java - Spring-boot JPA无限循环多对多
- java - 如何在 Spinner 中进行分组
- c# - 使用 Azure 函数更新本地 AD 用户配置文件
- node.js - NodeJS:Multer不保存文件
- java - 尝试在 java 和 IntelliJ Idea 中运行我的第一个链表程序会引发这些错误
- javascript - 如何在 Flask 中获取 JavaScript 输出
- typescript - 在 Typescript 中解构组合类型的所有属性
- javascript - 自定义域 apache 配置
- apache-flink - 检测到“execution.runtime-mode”设置为“BATCH”的 UNBOUNDED 源
- java - 为什么 Mono.doOnError 打印错误日志