RE2 регулярные выражения на потоках?

Можно ли использовать Google RE2 с потоками? Некоторые входные литералы, которые мы предполагаем обрабатывать с помощью регулярных выражений, могут быть слишком большими для хранения в памяти.

1 ответ

Если есть максимальная длина совпадения, вы можете прочитать данные в блоках по крайней мере вдвое больше этой длины. Если совпадение не удается или начинается меньше, чем столько символов с конца, обрежьте текущую строку и добавьте другой блок.

Длина строки соответствия никогда не будет больше, чем длина блока + максимальная длина соответствия.

Пример в C#:

public static IEnumerable<StreamMatch> MatchesInStream(
        this Regex pattern, TextReader reader,
        int maxMatchLength, int blockLength)
{
    if (maxMatchLength <= 0)
    {
        throw new ArgumentException("Must be positive", "maxMatchLength");
    }
    if (blockLength < maxMatchLength)
    {
        throw new ArgumentException("Must be at least as long as maxMatchLength", "blockLength");
    }

    char[] buffer = new char[blockLength];
    string chunk = "";
    int matchOffset = 0;

    // Read one block, and append to the string
    int charsRead = reader.ReadBlock(buffer, 0, blockLength);
    chunk += new string(buffer, 0, charsRead);

    while (charsRead > 0 && chunk.Length > maxMatchLength)
    {
        int cutPosition = 0;
        foreach (Match match in pattern.Matches(chunk))
        {
            if (match.Index > chunk.Length - maxMatchLength)
            {
                // The match could possibly have matched more characters.
                // Read another block before trying again.
                break;
            }

            yield return new StreamMatch(matchOffset, match);
            cutPosition = match.Index + match.Length;
        }
        cutPosition = Math.Max(cutPosition, chunk.Length - maxMatchLength);
        matchOffset += cutPosition;
        chunk = chunk.Substring(cutPosition);

        charsRead = reader.ReadBlock(buffer, 0, blockLength);
        chunk += new string(buffer, 0, charsRead);
    }

    // Stream has ended. Try to match the last remaining characters.
    foreach (Match match in pattern.Matches(chunk))
    {
        yield return new StreamMatch(matchOffset, match);
    }
}

public class StreamMatch
{
    public int MatchOffset { get; private set; }
    public Match Match { get; private set; }

    public StreamMatch(int matchOffset, Match match)
    {
        MatchOffset = matchOffset;
        Match = match;
    }
}
// One horrible XML parser
var reader = new StreamReader(stream);
var pattern = new Regex(@"<(/?)([\w:-]{1,15})([^<>]{0,50}(?<!/))(/?)>");
foreach (StreamMatch match in pattern.MatchesInStream(reader, 69, 128))
{
    Console.WriteLine(match.Match.Value);
}
Другие вопросы по тегам