Exemple #1
0
        /// <summary>
        /// Goes through <paramref name="m"/> matches and fill <paramref name="matches"/> array with results
        /// according to Set Order.
        /// </summary>
        /// <param name="r"><see cref="Regex"/> that produced the match</param>
        /// <param name="m"><see cref="Match"/> to iterate through all matches by NextMatch() call.</param>
        /// <param name="matches">Array for storing results.</param>
        /// <param name="addOffsets">Whether or not add arrays with offsets instead of strings.</param>
        /// <returns>Number of full pattern matches.</returns>
        static int FillMatchesArrayAllSetOrder(PerlRegex.Regex r, PerlRegex.Match m, ref PhpArray matches, bool addOffsets)
        {
            // first index, increases at each match in set order
            int i = 0;

            while (m.Success)
            {
                var pa = new PhpArray(m.Groups.Count);

                // add all groups
                for (int j = 0; j < m.Groups.Count; j++)
                {
                    var arr = NewArrayItem(m.Groups[j].Value, m.Groups[j].Index, addOffsets);

                    AddGroupNameToResult(r, pa, j, (p, groupName) =>
                    {
                        p[groupName] = arr;
                    });

                    pa[j] = arr;
                }

                matches[i] = (PhpValue)pa;
                i++;
                m = m.NextMatch();
            }

            return(i);
        }
Exemple #2
0
        public static PhpArray preg_grep(Context ctx, string pattern, PhpArray input, int flags = 0)
        {
            if (input == null)
            {
                return(null);
            }

            var result = new PhpArray(input.Count);

            if (input.Count != 0)
            {
                var regex = new PerlRegex.Regex(pattern);

                var enumerator = input.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var str = enumerator.CurrentValue.ToStringOrThrow(ctx);
                    var m   = regex.Match(str);

                    // move a copy to return array if success and not invert or
                    // not success and invert
                    if (m.Success ^ (flags & PREG_GREP_INVERT) != 0)
                    {
                        result.Add(enumerator.CurrentKey, enumerator.CurrentValue.DeepCopy());
                    }
                }
            }

            //
            return(result);
        }
Exemple #3
0
        /// <summary>
        /// Goes through <paramref name="m"/> matches and fill <paramref name="matches"/> array with results
        /// according to Pattern Order.
        /// </summary>
        /// <param name="r"><see cref="Regex"/> that produced the match</param>
        /// <param name="m"><see cref="Match"/> to iterate through all matches by NextMatch() call.</param>
        /// <param name="matches">Array for storing results.</param>
        /// <param name="addOffsets">Whether or not add arrays with offsets instead of strings.</param>
        /// <returns>Number of full pattern matches.</returns>
        static int FillMatchesArrayAllPatternOrder(PerlRegex.Regex r, PerlRegex.Match m, ref PhpArray matches, bool addOffsets)
        {
            // second index, increases at each match in pattern order
            int j = 0;

            while (m.Success)
            {
                // add all groups
                for (int i = 0; i < m.Groups.Count; i++)
                {
                    var arr = NewArrayItem(m.Groups[i].Value, m.Groups[i].Index, addOffsets);

                    AddGroupNameToResult(r, matches, i, (ms, groupName) =>
                    {
                        if (j == 0)
                        {
                            ms[groupName] = (PhpValue) new PhpArray();
                        }
                        ((PhpArray)ms[groupName])[j] = arr;
                    });

                    if (j == 0)
                    {
                        matches[i] = (PhpValue) new PhpArray();
                    }
                    ((PhpArray)matches[i])[j] = arr;
                }

                j++;
                m = m.NextMatch();
            }

            return(j);
        }
Exemple #4
0
        static void AddGroupNameToResult(PerlRegex.Regex regex, PhpArray matches, int i, Action <PhpArray, string> action)
        {
            var groupName = GetGroupName(regex, i);

            if (!string.IsNullOrEmpty(groupName))
            {
                action(matches, groupName);
            }
        }
Exemple #5
0
        static string GetGroupName(PerlRegex.Regex regex, int index)
        {
            var name = regex.GroupNameFromNumber(index);

            // anonymous groups and indexed groups:
            if (string.IsNullOrEmpty(name) || name.Equals(index.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat)))
            {
                name = null;
            }

            return(name);
        }
Exemple #6
0
            protected override int Count(int countPatternIndex, string sequences)
            {
                var r     = new PcreRegex.Regex(PcreCountPatterns[countPatternIndex]);
                int count = 0;

                for (var m = r.Match(sequences); m.Success; m = m.NextMatch())
                {
                    count++;
                }

                return(count);
            }
Exemple #7
0
        static PhpValue PregReplaceInternal(Context ctx, string pattern, string replacement, IPhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // callback
            PerlRegex.MatchEvaluator evaluator = null;
            if (callback != null)
            {
                evaluator = (match) =>
                {
                    var matches_arr = new PhpArray(0);
                    GroupsToPhpArray(match.PcreGroups, false, matches_arr);

                    return(callback
                           .Invoke(ctx, (PhpValue)matches_arr)
                           .ToStringOrThrow(ctx));
                };
            }

            // TODO: subject as a binary string would be corrupted after Replace - https://github.com/peachpiecompiler/peachpie/issues/178

            //
            var subject_array = subject.AsArray();

            if (subject_array == null)
            {
                return(PhpValue.Create(
                           evaluator == null
                        ? regex.Replace(subject.ToStringOrThrow(ctx), replacement, limit, ref count)
                        : regex.Replace(subject.ToStringOrThrow(ctx), evaluator, limit, ref count)));
            }
            else
            {
                var arr = new PhpArray(subject_array.Count);

                var enumerator = subject_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var newvalue = evaluator == null
                        ? regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), replacement, limit, ref count)
                        : regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), evaluator, limit, ref count);

                    // TODO: trick on how to quickly update values od enumerated array without hashing:
                    // enumerator.CurrentValue = PhpValue.Create(newvalue);

                    arr[enumerator.CurrentKey] = newvalue;
                }

                return(PhpValue.Create(arr));
            }
        }
 void pcrePatternCheck(string name, BoundExpression patternExpression)
 {
     if (patternExpression.ConstantValue.TryConvertToString(out var pattern))
     {
         try
         {
             var regex = new PerlRegex.Regex(pattern);
         }
         catch (PerlRegex.RegexParseException error)
         {
             _diagnostics.Add(
                 _routine, patternExpression.GetTextSpan(),
                 ErrorCode.WRN_PCRE_Pattern_Error, error.Message, error.Offset.HasValue ? error.Offset.Value.ToString() : "unknown");
         }
     }
 }
Exemple #9
0
        /// <summary>
        /// Goes through <paramref name="m"/> matches and fill <paramref name="matches"/> array with results
        /// according to Pattern Order.
        /// </summary>
        /// <param name="r"><see cref="Regex"/> that produced the match</param>
        /// <param name="m"><see cref="Match"/> to iterate through all matches by NextMatch() call.</param>
        /// <param name="matches">Array for storing results.</param>
        /// <param name="addOffsets">Whether or not add arrays with offsets instead of strings.</param>
        /// <returns>Number of full pattern matches.</returns>
        static int FillMatchesArrayAllPatternOrder(PerlRegex.Regex r, PerlRegex.Match m, ref PhpArray matches, bool addOffsets)
        {
            // second index, increases at each match in pattern order
            int j = 0;

            while (m.Success)
            {
                // add all groups
                for (int i = 0; i < m.Groups.Count; i++)
                {
                    var arr = NewArrayItem(m.Groups[i].Value, m.Groups[i].Index, addOffsets);

                    AddGroupNameToResult(r, matches, i, (ms, groupName) =>
                    {
                        if (!ms.TryGetValue(groupName, out var groupValue) || !groupValue.IsPhpArray(out var group))
                        {
                            ms[groupName] = group = new PhpArray();
                        }

                        group[j] = arr; // TODO: DeepCopy ?
                    });
Exemple #10
0
        static bool TryParseRegexp(string pattern, out PerlRegex.Regex regex)
        {
            try
            {
                regex = new PerlRegex.Regex(pattern);
            }
            catch (PerlRegex.RegexParseException error)
            {
                PhpException.Throw(
                    PhpError.Warning,
                    error.Offset > 0 // .HasValue
                        ? string.Format(LibResources.pcre_make_error, error.Message, error.Offset.ToString())
                        : error.Message
                    );

                regex = null;
            }

            //
            return(regex != null);
        }
Exemple #11
0
        public static PhpArray preg_split(string pattern, string subject, int limit = -1, int flags = 0)
        {
            if (limit == 0) // 0 does not make sense, php's behavior is as it is -1
            {
                limit = -1;
            }
            if (limit < -1) // for all other negative values it seems that is as limit == 1
            {
                limit = 1;
            }

            if (string.IsNullOrEmpty(pattern))
            {
                return(null); // FALSE
            }

            if (subject == null)
            {
                subject = string.Empty;
            }

            var regex = new PerlRegex.Regex(pattern);

            //if (!regex.IsValid) return null;

            var m = regex.Match(subject);

            bool offset_capture = (flags & PREG_SPLIT_OFFSET_CAPTURE) != 0;
            var  result         = new PhpArray();
            int  last_index     = 0;

            while (m.Success && (limit == -1 || --limit > 0) && last_index < subject.Length)
            {
                // add part before match
                int length = m.Index - last_index;
                if (length > 0 || (flags & PREG_SPLIT_NO_EMPTY) == 0)
                {
                    result.Add(NewArrayItem(subject.Substring(last_index, length), last_index, offset_capture));
                }

                if (m.Value.Length > 0)
                {
                    if ((flags & PREG_SPLIT_DELIM_CAPTURE) != 0)    // add all captures but not whole pattern match (start at 1)
                    {
                        List <object> lastUnsucessfulGroups = null; // value of groups that was not successful since last succesful one
                        for (int i = 1; i < m.Groups.Count; i++)
                        {
                            var g = m.Groups[i];
                            if (g.Length > 0 || (flags & PREG_SPLIT_NO_EMPTY) == 0)
                            {
                                // the value to be added into the result:
                                object value = NewArrayItem(g.Value, g.Index, offset_capture);

                                if (g.Success)
                                {
                                    // group {i} was matched:
                                    // if there was some unsuccesfull matches before, add them now:
                                    if (lastUnsucessfulGroups != null && lastUnsucessfulGroups.Count > 0)
                                    {
                                        foreach (var x in lastUnsucessfulGroups)
                                        {
                                            result.Add(x);
                                        }
                                        lastUnsucessfulGroups.Clear();
                                    }
                                    // add the matched group:
                                    result.Add(value);
                                }
                                else
                                {
                                    // The match was unsuccesful, remember all the unsuccesful matches
                                    // and add them only if some succesful match will follow.
                                    // In PHP, unsuccessfully matched groups are trimmed by the end
                                    // (regexp processing stops when other groups cannot be matched):
                                    if (lastUnsucessfulGroups == null)
                                    {
                                        lastUnsucessfulGroups = new List <object>();
                                    }
                                    lastUnsucessfulGroups.Add(value);
                                }
                            }
                        }
                    }

                    last_index = m.Index + m.Length;
                }
                else // regular expression match an empty string => add one character
                {
                    // always not empty
                    result.Add(NewArrayItem(subject.Substring(last_index, 1), last_index, offset_capture));
                    last_index++;
                }

                m = m.NextMatch();
            }

            // add remaining string (might be empty)
            if (last_index < subject.Length || (flags & PREG_SPLIT_NO_EMPTY) == 0)
            {
                result.Add(NewArrayItem(subject.Substring(last_index), last_index, offset_capture));
            }

            return(result);
        }
Exemple #12
0
        /// <summary>
        /// Perform a regular expression match.
        /// </summary>
        static int Match(Context ctx, string pattern, string subject, out PhpArray matches, int flags, long offset, bool matchAll)
        {
            subject = subject ?? string.Empty;

            var regex = new PerlRegex.Regex(pattern);
            var m     = regex.Match(subject, (offset < subject.Length) ? (int)offset : subject.Length);

            if ((regex.Options & PerlRegex.RegexOptions.PCRE_ANCHORED) != 0 && m.Success && m.Index != offset)
            {
                matches = PhpArray.NewEmpty();
                return(-1);
            }

            if (m.Success)
            {
                if (!matchAll || (flags & PREG_PATTERN_ORDER) != 0)
                {
                    matches = new PhpArray(m.Groups.Count);
                }
                else
                {
                    matches = new PhpArray();
                }

                if (!matchAll)
                {
                    GroupsToPhpArray(m.PcreGroups, (flags & PREG_OFFSET_CAPTURE) != 0, matches);
                    return(1);
                }

                // store all other matches in PhpArray matches
                if ((flags & PREG_SET_ORDER) != 0) // cannot test PatternOrder, it is 0, SetOrder must be tested
                {
                    return(FillMatchesArrayAllSetOrder(regex, m, ref matches, (flags & PREG_OFFSET_CAPTURE) != 0));
                }
                else
                {
                    return(FillMatchesArrayAllPatternOrder(regex, m, ref matches, (flags & PREG_OFFSET_CAPTURE) != 0));
                }
            }

            // no match has been found
            if (matchAll && (flags & PREG_SET_ORDER) == 0)
            {
                // in that case PHP returns an array filled with empty arrays according to parentheses count
                matches = new PhpArray(m.Groups.Count);
                for (int i = 0; i < regex.GetGroupNumbers().Length; i++)
                {
                    AddGroupNameToResult(regex, matches, i, (ms, groupName) =>
                    {
                        ms[groupName] = (PhpValue) new PhpArray();
                    });

                    matches[i] = (PhpValue) new PhpArray();
                }
            }
            else
            {
                matches = PhpArray.NewEmpty(); // empty array
            }

            return(0);
        }
Exemple #13
0
        public static int preg_match(Context ctx, string pattern, string subject)
        {
            var regex = new PerlRegex.Regex(pattern);

            return(regex.Match(subject ?? string.Empty).Success ? 1 : 0);
        }
Exemple #14
0
        static PhpValue PregReplaceInternal(Context ctx, string pattern, string replacement, IPhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // callback
            PerlRegex.MatchEvaluator evaluator = null;
            if (callback != null)
            {
                evaluator = (match) =>
                {
                    var matches_arr = new PhpArray();
                    GroupsToPhpArray(match.PcreGroups, false, matches_arr);

                    return(callback
                           .Invoke(ctx, (PhpValue)matches_arr)
                           .ToStringOrThrow(ctx));
                };
            }

            // TODO: subject as a binary string would be corrupted after Replace - https://github.com/peachpiecompiler/peachpie/issues/178

            //
            var subject_array = subject.AsArray();

            if (subject_array != null)
            {
                var arr = new PhpArray(subject_array.Count);

                var enumerator = subject_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var input    = enumerator.CurrentValue;
                    var oldvalue = input.ToStringOrThrow(ctx);
                    var oldcount = count;

                    var newvalue = evaluator == null
                        ? regex.Replace(oldvalue, replacement, limit, ref count)
                        : regex.Replace(oldvalue, evaluator, limit, ref count);

                    // - quick workaround for https://github.com/peachpiecompiler/peachpie/issues/178
                    // - use the original value if possible (mem perf.)

                    arr[enumerator.CurrentKey] = (oldcount == count)
                        ? (input.IsBinaryString(out var bstring) ? bstring.DeepCopy() : oldvalue)
                        : newvalue;
                }

                return(arr);
            }
            else
            {
                var oldvalue = subject.ToStringOrThrow(ctx);
                var oldcount = count;

                var newvalue = evaluator == null
                        ? regex.Replace(oldvalue, replacement, limit, ref count)
                        : regex.Replace(oldvalue, evaluator, limit, ref count);

                // - quick workaround for https://github.com/peachpiecompiler/peachpie/issues/178
                // - use the original value if possible (mem perf.)

                return((oldcount == count)
                    ? (subject.IsBinaryString(out var bstring) ? bstring.DeepCopy() : oldvalue)
                    : newvalue);
            }
        }