Browse Source

[add][refs #23] jsonDiff build a list of modifications, all we need now is to print it

isundil 9 years ago
parent
commit
8c42505a3f

+ 2 - 0
include/curseSplitOutput.hh

@@ -2,6 +2,7 @@
 
 #include <deque>
 #include "curseOutput.hh"
+#include "levenshtein.hpp"
 
 class CurseSplitOutput: public CurseOutput
 {
@@ -77,6 +78,7 @@ class CurseSplitOutput: public CurseOutput
          * currently searching pattern and its results
         **/
         std::deque<std::list<const JSonElement*> > search_result;
+        std::list<ePath> diffResult;
 
         /**
          * Viewport start

+ 65 - 25
include/levenshtein.hh → include/levenshtein.hpp

@@ -5,8 +5,6 @@
 #include <limits.h>
 #include "jsonElement.hh"
 
-#include <iostream>
-
 #define LEVENSHTEIN_SENSIBILITY (0.7f)
 
 float levenshteinPercent(const std::string &a, const std::string &b);
@@ -38,14 +36,6 @@ static SIZE **_levenshteinMatrice(const ITERATOR &aBegin, const ITERATOR &aEnd,
                     matrice[i][j -1] +1),
                     matrice[i -1][j -1] + ((levenshteinCompare(*a, *b) > LEVENSHTEIN_SENSIBILITY) ? 0 : 1));
     }
-
-    std::cerr << "<------" << std::endl;
-    for (size_t i=0; i <= lenA; ++i)
-    {
-        for (size_t j=0; j <= lenB; ++j)
-            std::cerr << (size_t) matrice[i][j] << "\t";
-        std::cerr << std::endl;
-    }
     return matrice;
 };
 
@@ -98,9 +88,11 @@ enum ePath: char
 };
 
 template<typename SIZE, class ITERATOR, class SUBTYPE>
-static std::list<ePath> _levenshteinShortestPath(ITERATOR aBegin, ITERATOR aEnd, ITERATOR bBegin, ITERATOR bEnd, size_t lenA, size_t lenB)
+static size_t _levenshteinShortestPath(std::list<ePath> &result, ITERATOR aBegin, ITERATOR aEnd, ITERATOR bBegin, ITERATOR bEnd, size_t lenA, size_t lenB)
 {
-    std::list<ePath> result(std::max(lenA, lenB));
+    const size_t initLenA = lenA;
+    const size_t initLenB = lenB;
+    result.clear();
 
     while (aBegin != aEnd && bBegin != bEnd && levenshteinCompare(*aBegin, *bBegin))
     {
@@ -110,36 +102,84 @@ static std::list<ePath> _levenshteinShortestPath(ITERATOR aBegin, ITERATOR aEnd,
         lenB--;
     }
     if (!lenA && !lenB)
-        ; //TODO create deque<ePath>(std::max(lenA, lenB) populated with '='
+    {
+        for (size_t i=0; i < initLenA; ++i)
+            result.push_back(ePath::equ);
+        return 0;
+    }
     else if (!lenA)
-        ; //TODO create deque<ePath>(std::max(lenA, lenB) populated with '=' then '-' and return it
+    {
+        size_t i;
+        for (i=0; i < initLenB - lenB; ++i)
+            result.push_back(ePath::equ);
+        for (; i < initLenB; ++i)
+            result.push_back(ePath::rem);
+        return lenB;
+    }
     else if (!lenB)
-        ; //TODO create deque<ePath>(std::max(lenA, lenB) populated with '=' then '+' and return it
+    {
+        size_t i;
+        for (i=0; i < initLenA - lenA; ++i)
+            result.push_back(ePath::equ);
+        for (; i < initLenA; ++i)
+            result.push_back(ePath::add);
+        return lenA;
+    }
     SIZE **matrice = _levenshteinMatrice<SIZE, ITERATOR, SUBTYPE>(aBegin, aEnd, bBegin, bEnd, lenA, lenB);
-    size_t i;
+    size_t i = lenA;
+    size_t j = lenB;
+    const size_t levenDist = matrice[i][j];
 
-    //TODO find shortest path
-    // - goto bottom right
-    // - go back to top left going decrement ONLY (or =, if not possible)
+    while (i || j)
+    {
+        if (i && (!j || matrice[i][j] > matrice[i-1][j]))
+        {
+            result.push_front(ePath::add);
+            --i;
+        }
+        else if (j && (!i || matrice[i][j] > matrice[i][j -1]))
+        {
+            result.push_front(ePath::rem);
+            --j;
+        }
+        else if (i && j)
+        {
+            result.push_front(matrice[i][j] == matrice[i-1][j-1] ? ePath::equ : ePath::mod);
+            --i;
+            --j;
+        }
+        else if (i)
+        {
+            result.push_front(ePath::add);
+            --i;
+        }
+        else if (j)
+        {
+            result.push_front(ePath::rem);
+            --j;
+        }
+    }
 
+    for (i = initLenA - lenA; i; --i)
+        result.push_front(ePath::equ);
 
     // Clean matrice
-    for (i=0; i < lenA; ++i)
+    for (i=0; i < lenA +1; ++i)
         delete[] matrice[i];
     delete[] matrice;
-    return result;
+    return levenDist;
 };
 
 template<class T>
-std::list<ePath> levenshteinShortestPath(const std::list<T*> *a, const std::list<T *> *b)
+size_t levenshteinShortestPath(std::list<ePath> &result, const std::list<T*> *a, const std::list<T *> *b)
 {
     const size_t lenA = a->size();
     const size_t lenB = b->size();
 
     if (lenA < UCHAR_MAX && lenB < UCHAR_MAX)
-        return _levenshteinShortestPath<unsigned char, typename std::list<T *>::const_iterator, T *>(a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
+        return _levenshteinShortestPath<unsigned char, typename std::list<T *>::const_iterator, T *>(result, a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
     if (lenA < USHRT_MAX && lenB < USHRT_MAX)
-        return _levenshteinShortestPath<unsigned short, typename std::list<T *>::const_iterator, T *>(a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
-    return _levenshteinShortestPath<unsigned int, typename std::list<T *>::const_iterator, T *>(a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
+        return _levenshteinShortestPath<unsigned short, typename std::list<T *>::const_iterator, T *>(result, a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
+    return _levenshteinShortestPath<unsigned int, typename std::list<T *>::const_iterator, T *>(result, a->cbegin(), a->cend(), b->cbegin(), b->cend(), lenA, lenB);
 }
 

+ 2 - 7
src/curseSplitOutput.cpp

@@ -15,11 +15,9 @@
 #include "jsonArray.hh"
 #include "jsonPrimitive.hh"
 
-#include "levenshtein.hh"
-
 CurseSplitOutput::CurseSplitOutput(const Params &p): CurseOutput(p)
 {
-    //init();
+    init();
 }
 
 CurseSplitOutput::~CurseSplitOutput()
@@ -31,11 +29,8 @@ void CurseSplitOutput::run(const std::deque<std::string> &inputName, const std::
 {
     const JSonArray *a = (const JSonArray*)roots.at(0);
     const JSonArray *b = (const JSonArray*)roots.at(1);
-    levenshteinShortestPath<JSonElement>(a, b);
-    return;
-
-
 
+    levenshteinShortestPath<JSonElement>(diffResult, a, b); // FIXME Will fail if 3 inputs
 
     nbInputs = inputName.size();
     selectedWin = 0;

+ 1 - 1
src/jsonContainer.cpp

@@ -5,7 +5,7 @@
 **/
 
 #include "jsonContainer.hh"
-#include "levenshtein.hh"
+#include "levenshtein.hpp"
 
 JSonContainer::JSonContainer(JSonContainer *p):JSonElement(p)
 { }

+ 4 - 2
src/jsonElement.cpp

@@ -8,7 +8,7 @@
 #include "jsonContainer.hh"
 #include "jsonObjectEntry.hh"
 #include "searchPattern.hh"
-#include "levenshtein.hh"
+#include "levenshtein.hpp"
 
 JSonElement::JSonElement(JSonElement *p): parent(p), _strlen(0)
 { }
@@ -110,7 +110,9 @@ bool JSonElement::match(const SearchPattern &searchPattern) const
 
 float JSonElement::diff(const JSonElement *o) const
 {
-    // TODO check if o is a container
+    if (dynamic_cast<const JSonContainer*>(o) ||
+            dynamic_cast<const JSonObjectEntry*>(o))
+        return 0.f;
     return levenshteinPercent(stringify(), o->stringify());
 }
 

+ 2 - 2
src/levenshtein.cpp

@@ -1,11 +1,11 @@
-#include <iostream>
-#include "levenshtein.hh"
+#include "levenshtein.hpp"
 
 float levenshteinPercent(const std::string &a, const std::string &b)
 {
     const size_t lenA = a.size();
     const size_t lenB = b.size();
 
+    if (a == b) return 1.f;
     if (lenA < UCHAR_MAX && lenB < UCHAR_MAX)
         return _levenshteinPercent<unsigned char, std::string::const_iterator, char>(a.begin(), a.end(), b.begin(), b.end(), lenA, lenB);
     if (lenA < USHRT_MAX && lenB < USHRT_MAX)

+ 17 - 9
test/src/levenshtein_test.cpp

@@ -1,27 +1,35 @@
 #include <iostream>
-#include "levenshtein.hh"
+#include "levenshtein.hpp"
 
 #define FAILED(got, op, expt) {std::cout << __FILE__ << ":" << __LINE__ << ": failed asserting " << got << " " << op << " expected " << expt << std::endl; return false; }
 
+/*
+size_t levenshteinShortestPath(const std::string &a, const std::string &b)
+{
+    std::list<ePath> r;
+    return levenshteinShortestPath(r, a, b);
+}
+*/
+
 bool doTest()
 {
+    /*
     float pc;
     unsigned int lev;
 
-    /*
-    if ((lev = levenshtein("coucou", "coucou")) != 0)
+    if ((lev = levenshteinShortestPath("coucou", "coucou")) != 0)
         FAILED(lev, "!=", 0);
-    if ((pc = levenshteinPercent("coucou", "coucou")) != 1)
+    if ((pc = levenshteinShortestPath("coucou", "coucou")) != 1)
         FAILED(pc, "!=", 1);
-    if ((lev = levenshtein("coocou", "coucou")) != 1)
+    if ((lev = levenshteinShortestPath("coocou", "coucou")) != 1)
         FAILED(lev, "!=", 1);
-    if ((lev = levenshtein("abcdefghijk", "zabcdefghijk")) != 1)
+    if ((lev = levenshteinShortestPath("abcdefghijk", "zabcdefghijk")) != 1)
         FAILED(lev, "!=", 1);
-    if ((lev = levenshtein("zabcdefghijk", "abcdefghijk")) != 1)
+    if ((lev = levenshteinShortestPath("zabcdefghijk", "abcdefghijk")) != 1)
         FAILED(lev, "!=", 1);
-    if ((lev = levenshtein("zabcdefghijk", "zabcdkfghijk")) != 1)
+    if ((lev = levenshteinShortestPath("zabcdefghijk", "zabcdkfghijk")) != 1)
         FAILED(lev, "!=", 1);
-    if ((lev = levenshtein("a", "zabcdkfghijk")) != 11)
+    if ((lev = levenshteinShortestPath("a", "zabcdkfghijk")) != 11)
         FAILED(lev, "!=", 11);
     */
     return true;