【问题标题】:How to manipulate leaves of a JSON tree如何操作 JSON 树的叶子
【发布时间】:2013-04-18 22:10:05
【问题描述】:

我想使用 JAVA 将 JSON 树中的稀有词替换为 _RARE_

我的稀有词列表包含

late  
populate
convicts

所以对于下面的 JSON

["S", ["PP", ["ADP", "In"], ["NP", ["DET", "the"], ["NP", ["ADJ", "late"], ["NOUN", "1700<s"]]]], ["S", ["NP", ["ADJ", "British"], ["NOUN", "convicts"]], ["S", ["VP", ["VERB", "were"], ["VP", ["VERB", "used"], ["S+VP", ["PRT", "to"], ["VP", ["VERB", "populate"], ["WHNP", ["DET", "which"], ["NOUN", "colony"]]]]]], [".", "?"]]]]

我应该得到

["S", ["PP", ["ADP", "In"], ["NP", ["DET", "the"], ["NP", ["ADJ", "_RARE_"], ["NOUN", "1700<s"]]]], ["S", ["NP", ["ADJ", "British"], ["NOUN", "_RARE_"]], ["S", ["VP", ["VERB", "were"], ["VP", ["VERB", "used"], ["S+VP", ["PRT", "to"], ["VP", ["VERB", "populate"], ["WHNP", ["DET", "which"], ["NOUN", "colony"]]]]]], [".", "?"]]]]

注意方法

["ADJ","late"]

被替换为

["ADJ","_RARE_"]

到目前为止,我的代码如下:

我递归地遍历树,一旦找到稀有词,我就创建一个新的 JSON 数组并尝试用它替换现有树的节点。请参阅下面的// this Doesn't work,这就是我卡住的地方。树在此函数之外保持不变。

public static void traverseTreeAndReplaceWithRare(JsonArray tree){   

        //System.out.println(tree.getAsJsonArray()); 

        for (int x = 0; x < tree.getAsJsonArray().size(); x++)
        {
            if(!tree.get(x).isJsonArray())
            {
                if(tree.size()==2)
                {   
                //beware it will get here twice for same word
                 String word= tree.get(1).toString();  
                 word=word.replaceAll("\"", ""); // removing double quotes

                 if(rareWords.contains(word))
                 {
                 JsonParser parser = new JsonParser();                   

                             //This works perfectly 
                             System.out.println("Orig:"+tree);
                 JsonElement jsonElement = parser.parse("["+tree.get(0)+","+"_RARE_"+"]");

                 JsonArray newRareArray = jsonElement.getAsJsonArray();

                             //This works perfectly 
                             System.out.println("New:"+newRareArray);

                 tree=newRareArray; // this Doesn't work
                 }                 

                }               
                continue;   
            }
            traverseTreeAndReplaceWithRare(tree.get(x).getAsJsonArray());
        }
    }

上面的调用代码,我用google的gson

JsonParser parser = new JsonParser();
JsonElement jsonElement = parser.parse(strJSON);
JsonArray tree = jsonElement.getAsJsonArray();  

【问题讨论】:

  • 你为什么不做一个strJSON.replaceAll("(late|populate|convicts)", "_RARE_")
  • +1 当然,我将尝试这样做,它可能适用于大多数情况。但提出这个问题的主要动机是了解/学习如何操作这种树。
  • 抱歉,replaceAll() 对我不起作用,因为我的稀有词列表长 3435,而且它最终从 [ “SQ”、“迟到”]
  • 发生上述情况是因为有一个“S”。在我的稀有列表中.. 我刚刚通过所有 3435 个稀有词找到了。

标签: java json data-structures tree


【解决方案1】:

这是 C++ 中的一种直接方法:

#include <fstream>
#include "JSON.hpp"
#include <boost/algorithm/string/regex.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/phoenix.hpp>

static std::vector<std::wstring> readRareWordList()
{
    std::vector<std::wstring> result;

    std::wifstream ifs("testcases/rarewords.txt");
    std::wstring line;
    while (std::getline(ifs, line))
        result.push_back(std::move(line));

    return result;
}

struct RareWords : boost::static_visitor<> {

    /////////////////////////////////////
    // do nothing by default
    template <typename T> void operator()(T&&) const { /* leave all other things unchanged */ }

    /////////////////////////////////////
    // recurse arrays and objects
    void operator()(JSON::Object& obj) const { 
        for(auto& v : obj.values) {
            //RareWords::operator()(v.first); /* to replace in field names (?!) */
            boost::apply_visitor(*this, v.second);
        }
    }

    void operator()(JSON::Array& arr) const {
        int i = 0;
        for(auto& v : arr.values) {
            if (i++) // skip the first element in all arrays
                boost::apply_visitor(*this, v);
        }
    }

    /////////////////////////////////////
    // do replacements on strings
    void operator()(JSON::String& s) const {
        using namespace boost;

        const static std::vector<std::wstring> rareWords = readRareWordList();
        const static std::wstring replacement = L"__RARE__";

        for (auto&& word : rareWords)
            if (word == s.value)
                s.value = replacement;
    }
};

int main()
{
    auto document = JSON::readFrom(std::ifstream("testcases/test3.json"));

    boost::apply_visitor(RareWords(), document);

    std::cout << document;
}

这假设您想要对所有字符串值进行替换,并且只匹配整个字符串。您可以通过更改正则表达式或正则表达式标志轻松地使这种不区分大小写、匹配字符串中的单词等。根据 cmets 稍作调整。

包含 JSON.hpp/cpp 的完整代码在这里:https://github.com/sehe/spirit-v2-json/tree/16093940

【讨论】:

  • +1 获取代码,谢谢!因为我不太懂C++。您是否可以修改您的代码,以便我可以通过文件传递rareWords?实际上,为了便于阅读,我试图缩短我的问题,实际上我的稀有词列表包含 3435 个单词,其中一些是 contanis 。或 * 例如 S. U.S.A. A* 搞砸了 String.replaceAll Regex matching 。尝试更新代码后,我会接受这个答案。
  • 是的,从文件中读取单词非常简单。但是,我真的想要关于匹配什么的确切示例(你总是想要 whole stringsexact matches 吗?
  • 是的,完全匹配整个字符串。例如:如果“xyz”。在稀有词列表中,然后只有“xyz”。应替换为“RARE”,甚至不是“xyz”。如果某个数组类似于 ["xyz.","xyz." ] 它应该是 ["xyz.", "RARE"] ...注意分支数组中的第二个字符串被替换,我们从不接触第一个。 replaceAll 方法的另一个缺点是它可能会替换第一个字符串。为了更清晰,我将修改问题以绘制树。如果您需要,我可以共享整个输入和稀有Word 文件。
  • @Watt 更新为 readRareWordList() 并显示如何仅进行完全匹配。 EDIT 现在也跳过了每个数组中的第一个元素(见评论) 删除了我从您的代码中挑选的正则表达式匹配,但毕竟不是您想要的。
  • 谢谢!现在要试试这个.. 10-15 分钟后回来。
猜你喜欢
  • 2017-11-17
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
  • 2013-01-19
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多