简体   繁体   English

将带有特殊字符的字符串转换为 JSONObject

[英]Convert string with special characters to JSONObject

I've the input string coming as "{"notes_text": "someString"}" .我的输入字符串为"{"notes_text": "someString"}" someString can contain \ or ". And I need to make a JSONObject representing this string. someString 可以包含 \ 或 "。我需要创建一个 JSONObject 来表示这个字符串。

Simply using the constructor which takes a string as input will throw an exception if it contains special characters.如果它包含特殊字符,只需使用将字符串作为输入的构造函数将引发异常。

I've tried a couple of approaches to do this我已经尝试了几种方法来做到这一点

  • use a library to escape the characters - this would result in, for instance, "{\"notes_text\":\"\"\"}" or "{\"notes_text\":\"\\\"}" . and I would need to change these to "{\"notes_text\":\"\\\"\"}" and "{\"notes_text\":\"\\\\\"}" respectively or else it would again throw the exception while converting to JSON Object.使用库来转义字符 - 例如,这将导致"{\"notes_text\":\"\"\"}""{\"notes_text\":\"\\\"}" 。我需要将它们分别更改为"{\"notes_text\":\"\\\"\"}""{\"notes_text\":\"\\\\\"}"否则它会在转换为 JSON Object 时再次抛出异常。 Using the replace method in string will convert all the \" in the input string在字符串中使用 replace 方法将转换输入字符串中的所有 \"
  • don't escape the special chars in the input string and use string replace method to convert \ to \ and " to \".不要转义输入字符串中的特殊字符并使用字符串替换方法将\转换为\和“到\”。 But this would again replace all the double quotes in the input string但这将再次替换输入字符串中的所有双引号

I tried using regex but can't get my head around the replacement string in str.replaceAll("\\\".*\\\".*\\\"", replacemntString)我尝试使用正则表达式,但无法str.replaceAll("\\\".*\\\".*\\\"", replacemntString)中的替换字符串

Classes课程

Here are two classes that solve initial problem with broken json:这是解决 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");
    }
}

Unit-tests单元测试

And I've written unit-tests to prove the correctness:我已经编写了单元测试来证明正确性:

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"
        );
    }
}

Full working example完整的工作示例

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");
        }
    }
}

And its STDOUT:及其标准输出:

fixedJson = {"notes_text":"\""}

This JSON can be validated using following tool: https://jsonlint.com/此 JSON 可以使用以下工具进行验证: https://jsonlint.com/

Regex explanation正则表达式解释

FixedJson class FixedJson

The first class FixedJson uses regexp for matching JSON lemmas: everything between double quotes (include misplaced double quotes).第一个 class FixedJson使用正则表达式匹配 JSON 引理:双引号之间的所有内容(包括放错位置的双引号)。

For more details see an interactive example here: https://regexr.com/54blf有关更多详细信息,请参见此处的交互式示例: https://regexr.com/54blf

Escaped class Escaped class

The second class Escaped uses regexp for matching slashes or double quotes.第二个 class Escaped使用正则表达式来匹配斜杠或双引号。 It's required for their escaping.他们的 escaping 需要它。

For more details see an interactive example here: https://regexr.com/54bm1有关更多详细信息,请参见此处的交互式示例: https://regexr.com/54bm1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM