コード例 #1
0
        //  PATCH FUNCTIONS
        /**
         * Increase the context until it is unique,
         * but don't let the pattern expand beyond Match_MaxBits.
         * @param patch The patch to grow.
         * @param text Source text.
         */
        protected void patch_addContext(Patch patch, string text)
        {
            if (text.Length == 0)
            {
                return;
            }
            string pattern = text.Substring(patch.start2, patch.length1);
            int padding = 0;

            // Look for the first and last matches of pattern in text.  If two
            // different matches are found, increase the pattern length.
            while (text.IndexOf(pattern, StringComparison.Ordinal)
                != text.LastIndexOf(pattern, StringComparison.Ordinal)
                && pattern.Length < Match_MaxBits - Patch_Margin - Patch_Margin)
            {
                padding += Patch_Margin;
                pattern = text.JavaSubstring(Math.Max(0, patch.start2 - padding),
                    Math.Min(text.Length, patch.start2 + patch.length1 + padding));
            }
            // Add one chunk for good luck.
            padding += Patch_Margin;

            // Add the prefix.
            string prefix = text.JavaSubstring(Math.Max(0, patch.start2 - padding),
              patch.start2);
            if (prefix.Length != 0)
            {
                patch.diffs.Insert(0, new Diff(Operation.EQUAL, prefix));
            }
            // Add the suffix.
            string suffix = text.JavaSubstring(patch.start2 + patch.length1,
                Math.Min(text.Length, patch.start2 + patch.length1 + padding));
            if (suffix.Length != 0)
            {
                patch.diffs.Add(new Diff(Operation.EQUAL, suffix));
            }

            // Roll back the start points.
            patch.start1 -= prefix.Length;
            patch.start2 -= prefix.Length;
            // Extend the lengths.
            patch.length1 += prefix.Length + suffix.Length;
            patch.length2 += prefix.Length + suffix.Length;
        }
コード例 #2
0
        /**
         * Look through the patches and break up any which are longer than the
         * maximum limit of the match algorithm.
         * Intended to be called only from within patch_apply.
         * @param patches List of Patch objects.
         */
        public void patch_splitMax(List<Patch> patches)
        {
            short patch_size = this.Match_MaxBits;
            for (int x = 0; x < patches.Count; x++)
            {
                if (patches[x].length1 <= patch_size)
                {
                    continue;
                }
                Patch bigpatch = patches[x];
                // Remove the big old patch.
                patches.Splice(x--, 1);
                int start1 = bigpatch.start1;
                int start2 = bigpatch.start2;
                string precontext = string.Empty;
                while (bigpatch.diffs.Count != 0)
                {
                    // Create one of several smaller patches.
                    Patch patch = new Patch();
                    bool empty = true;
                    patch.start1 = start1 - precontext.Length;
                    patch.start2 = start2 - precontext.Length;
                    if (precontext.Length != 0)
                    {
                        patch.length1 = patch.length2 = precontext.Length;
                        patch.diffs.Add(new Diff(Operation.EQUAL, precontext));
                    }
                    while (bigpatch.diffs.Count != 0
                        && patch.length1 < patch_size - this.Patch_Margin)
                    {
                        Operation diff_type = bigpatch.diffs[0].operation;
                        string diff_text = bigpatch.diffs[0].text;
                        if (diff_type == Operation.INSERT)
                        {
                            // Insertions are harmless.
                            patch.length2 += diff_text.Length;
                            start2 += diff_text.Length;
                            patch.diffs.Add(bigpatch.diffs.First());
                            bigpatch.diffs.RemoveAt(0);
                            empty = false;
                        }
                        else if (diff_type == Operation.DELETE && patch.diffs.Count == 1
                          && patch.diffs.First().operation == Operation.EQUAL
                          && diff_text.Length > 2 * patch_size)
                        {
                            // This is a large deletion.  Let it pass in one chunk.
                            patch.length1 += diff_text.Length;
                            start1 += diff_text.Length;
                            empty = false;
                            patch.diffs.Add(new Diff(diff_type, diff_text));
                            bigpatch.diffs.RemoveAt(0);
                        }
                        else
                        {
                            // Deletion or equality.  Only take as much as we can stomach.
                            diff_text = diff_text.Substring(0, Math.Min(diff_text.Length,
                                patch_size - patch.length1 - Patch_Margin));
                            patch.length1 += diff_text.Length;
                            start1 += diff_text.Length;
                            if (diff_type == Operation.EQUAL)
                            {
                                patch.length2 += diff_text.Length;
                                start2 += diff_text.Length;
                            }
                            else
                            {
                                empty = false;
                            }
                            patch.diffs.Add(new Diff(diff_type, diff_text));
                            if (diff_text == bigpatch.diffs[0].text)
                            {
                                bigpatch.diffs.RemoveAt(0);
                            }
                            else
                            {
                                bigpatch.diffs[0].text =
                                    bigpatch.diffs[0].text.Substring(diff_text.Length);
                            }
                        }
                    }
                    // Compute the head context for the next patch.
                    precontext = this.diff_text2(patch.diffs);
                    precontext = precontext.Substring(Math.Max(0,
                        precontext.Length - this.Patch_Margin));

                    string postcontext = null;
                    // Append the end context for this patch.
                    if (diff_text1(bigpatch.diffs).Length > Patch_Margin)
                    {
                        postcontext = diff_text1(bigpatch.diffs)
                            .Substring(0, Patch_Margin);
                    }
                    else
                    {
                        postcontext = diff_text1(bigpatch.diffs);
                    }

                    if (postcontext.Length != 0)
                    {
                        patch.length1 += postcontext.Length;
                        patch.length2 += postcontext.Length;
                        if (patch.diffs.Count != 0
                            && patch.diffs[patch.diffs.Count - 1].operation
                            == Operation.EQUAL)
                        {
                            patch.diffs[patch.diffs.Count - 1].text += postcontext;
                        }
                        else
                        {
                            patch.diffs.Add(new Diff(Operation.EQUAL, postcontext));
                        }
                    }
                    if (!empty)
                    {
                        patches.Splice(++x, 0, patch);
                    }
                }
            }
        }
コード例 #3
0
        /**
         * Parse a textual representation of patches and return a List of Patch
         * objects.
         * @param textline Text representation of patches.
         * @return List of Patch objects.
         * @throws ArgumentException If invalid input.
         */
        public List<Patch> patch_fromText(string textline)
        {
            List<Patch> patches = new List<Patch>();
            if (textline.Length == 0)
            {
                return patches;
            }
            string[] text = textline.Split('\n');
            int textPointer = 0;
            Patch patch;
            Regex patchHeader
                = new Regex("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$");
            Match m;
            char sign;
            string line;
            while (textPointer < text.Length)
            {
                m = patchHeader.Match(text[textPointer]);
                if (!m.Success)
                {
                    throw new ArgumentException("Invalid patch string: "
                        + text[textPointer]);
                }
                patch = new Patch();
                patches.Add(patch);
                patch.start1 = Convert.ToInt32(m.Groups[1].Value);
                if (m.Groups[2].Length == 0)
                {
                    patch.start1--;
                    patch.length1 = 1;
                }
                else if (m.Groups[2].Value == "0")
                {
                    patch.length1 = 0;
                }
                else
                {
                    patch.start1--;
                    patch.length1 = Convert.ToInt32(m.Groups[2].Value);
                }

                patch.start2 = Convert.ToInt32(m.Groups[3].Value);
                if (m.Groups[4].Length == 0)
                {
                    patch.start2--;
                    patch.length2 = 1;
                }
                else if (m.Groups[4].Value == "0")
                {
                    patch.length2 = 0;
                }
                else
                {
                    patch.start2--;
                    patch.length2 = Convert.ToInt32(m.Groups[4].Value);
                }
                textPointer++;

                while (textPointer < text.Length)
                {
                    try
                    {
                        sign = text[textPointer][0];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        // Blank line?  Whatever.
                        textPointer++;
                        continue;
                    }
                    line = text[textPointer].Substring(1);
                    line = line.Replace("+", "%2b");
                    line = HttpUtility.UrlDecode(line, new UTF8Encoding(false, true));
                    if (sign == '-')
                    {
                        // Deletion.
                        patch.diffs.Add(new Diff(Operation.DELETE, line));
                    }
                    else if (sign == '+')
                    {
                        // Insertion.
                        patch.diffs.Add(new Diff(Operation.INSERT, line));
                    }
                    else if (sign == ' ')
                    {
                        // Minor equality.
                        patch.diffs.Add(new Diff(Operation.EQUAL, line));
                    }
                    else if (sign == '@')
                    {
                        // Start of next patch.
                        break;
                    }
                    else
                    {
                        // WTF?
                        throw new ArgumentException(
                            "Invalid patch mode '" + sign + "' in: " + line);
                    }
                    textPointer++;
                }
            }
            return patches;
        }
コード例 #4
0
        /**
         * Compute a list of patches to turn text1 into text2.
         * text2 is not provided, diffs are the delta between text1 and text2.
         * @param text1 Old text.
         * @param diffs Array of Diff objects for text1 to text2.
         * @return List of Patch objects.
         */
        public List<Patch> patch_make(string text1, List<Diff> diffs)
        {
            // Check for null inputs not needed since null can't be passed in C#.
            List<Patch> patches = new List<Patch>();
            if (diffs.Count == 0)
            {
                return patches;  // Get rid of the null case.
            }
            Patch patch = new Patch();
            int char_count1 = 0;  // Number of characters into the text1 string.
            int char_count2 = 0;  // Number of characters into the text2 string.
            // Start with text1 (prepatch_text) and apply the diffs until we arrive at
            // text2 (postpatch_text). We recreate the patches one by one to determine
            // context info.
            string prepatch_text = text1;
            string postpatch_text = text1;
            foreach (Diff aDiff in diffs)
            {
                if (patch.diffs.Count == 0 && aDiff.operation != Operation.EQUAL)
                {
                    // A new patch starts here.
                    patch.start1 = char_count1;
                    patch.start2 = char_count2;
                }

                switch (aDiff.operation)
                {
                    case Operation.INSERT:
                        patch.diffs.Add(aDiff);
                        patch.length2 += aDiff.text.Length;
                        postpatch_text = postpatch_text.Insert(char_count2, aDiff.text);
                        break;
                    case Operation.DELETE:
                        patch.length1 += aDiff.text.Length;
                        patch.diffs.Add(aDiff);
                        postpatch_text = postpatch_text.Remove(char_count2,
                            aDiff.text.Length);
                        break;
                    case Operation.EQUAL:
                        if (aDiff.text.Length <= 2 * Patch_Margin
                            && patch.diffs.Count() != 0 && aDiff != diffs.Last())
                        {
                            // Small equality inside a patch.
                            patch.diffs.Add(aDiff);
                            patch.length1 += aDiff.text.Length;
                            patch.length2 += aDiff.text.Length;
                        }

                        if (aDiff.text.Length >= 2 * Patch_Margin)
                        {
                            // Time for a new patch.
                            if (patch.diffs.Count != 0)
                            {
                                patch_addContext(patch, prepatch_text);
                                patches.Add(patch);
                                patch = new Patch();
                                // Unlike Unidiff, our patch lists have a rolling context.
                                // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
                                // Update prepatch text & pos to reflect the application of the
                                // just completed patch.
                                prepatch_text = postpatch_text;
                                char_count1 = char_count2;
                            }
                        }
                        break;
                }

                // Update the current character count.
                if (aDiff.operation != Operation.INSERT)
                {
                    char_count1 += aDiff.text.Length;
                }
                if (aDiff.operation != Operation.DELETE)
                {
                    char_count2 += aDiff.text.Length;
                }
            }
            // Pick up the leftover patch if not empty.
            if (patch.diffs.Count != 0)
            {
                patch_addContext(patch, prepatch_text);
                patches.Add(patch);
            }

            return patches;
        }
コード例 #5
0
 /**
  * Given an array of patches, return another array that is identical.
  * @param patches Array of Patch objects.
  * @return Array of Patch objects.
  */
 public List<Patch> patch_deepCopy(List<Patch> patches)
 {
     List<Patch> patchesCopy = new List<Patch>();
     foreach (Patch aPatch in patches)
     {
         Patch patchCopy = new Patch();
         foreach (Diff aDiff in aPatch.diffs)
         {
             Diff diffCopy = new Diff(aDiff.operation, aDiff.text);
             patchCopy.diffs.Add(diffCopy);
         }
         patchCopy.start1 = aPatch.start1;
         patchCopy.start2 = aPatch.start2;
         patchCopy.length1 = aPatch.length1;
         patchCopy.length2 = aPatch.length2;
         patchesCopy.Add(patchCopy);
     }
     return patchesCopy;
 }