Регулярные выражения.NET на байтах вместо символов

Я пытаюсь сделать некоторый парсинг, который будет более легкими регулярными выражениями использования.

Вход является массивом (или перечисление) байтов.

Я не хочу преобразовывать байты в символы по следующим причинам:

  1. Эффективность вычисления
  2. Эффективность потребления памяти
  3. Некоторые непечатаемые байты могли бы быть сложными для преобразования в символы. Не все байты являются печатаемыми.

Таким образом, я не могу использовать Regex.

Единственное решение, которое я знаю, использует Повышение. Regex (который работает над байтами - C символы), но это - библиотека C++, что обертывание использующий C++ / CLI возьмет значительную работу.

Как я могу использовать регулярные выражения на байтах в.NET непосредственно, не работая со строками.NET и символами?

Спасибо.

16
задан brickner 12 June 2010 в 13:09
поделиться

2 ответа

Здесь наблюдается небольшое несоответствие импеданса. Вы хотите работать с регулярными выражениями в .Net, которые используют строки (многобайтовые символы), но вы хотите работать с однобайтовыми символами. Вы не можете использовать оба одновременно, используя .Net, как обычно.

Однако, чтобы устранить это несоответствие, вы можете обработать строку побайтно-ориентированным образом и изменить ее. Затем измененная строка может действовать как повторно используемый буфер. Таким образом, вам не придется преобразовывать байты в символы или преобразовывать входной буфер в строку (согласно вашему вопросу).

Пример:

//BLING
byte[] inputBuffer = { 66, 76, 73, 78, 71 };

string stringBuffer = new string('\0', 1000);

Regex regex = new Regex("ING", RegexOptions.Compiled);

unsafe
{
    fixed (char* charArray = stringBuffer)
    {
        byte* buffer = (byte*)(charArray);

        //Hard-coded example of string mutation, in practice you would
        //loop over your input buffers and regex\match so that the string
        //buffer is re-used.

        buffer[0] = inputBuffer[0];
        buffer[2] = inputBuffer[1];
        buffer[4] = inputBuffer[2];
        buffer[6] = inputBuffer[3];
        buffer[8] = inputBuffer[4];

        Console.WriteLine("Mutated string:'{0}'.",
             stringBuffer.Substring(0, inputBuffer.Length));

        Match match = regex.Match(stringBuffer, 0, inputBuffer.Length);

        Console.WriteLine("Position:{0} Length:{1}.", match.Index, match.Length);
    }
}

Используя эту технику, вы можете выделить строковый «буфер», который можно повторно использовать в качестве входных данных для Regex, но вы можете каждый раз изменять его своими байтами.Это позволяет избежать накладных расходов на преобразование \ кодирование вашего массива байтов в новую строку .Net каждый раз, когда вы хотите выполнить сопоставление. Это может оказаться очень важным, поскольку я видел, как многие алгоритмы в .Net пытались разогнаться со скоростью миллион миль в час, но были поставлены на колени из-за генерации строки и последующего спама в куче и времени, проведенного в GC.

Очевидно, что это небезопасный код, но это .Net.

Однако результаты Regex будут генерировать строки, так что здесь у вас есть проблема. Я не уверен, есть ли способ использовать Regex, который не будет генерировать новые строки. Вы, конечно, можете получить информацию об индексе совпадения и длине, но генерация строки нарушает ваши требования к эффективности памяти.

Обновление

На самом деле после дизассемблирования Regex \ Match \ Group \ Capture похоже, что он генерирует захваченную строку только при доступе к свойству Value, поэтому вы можете, по крайней мере, не создавать строки, если вы обращаетесь только к индексу и длине характеристики. Однако вы будете генерировать все поддерживающие объекты Regex.

8
ответ дан 30 November 2019 в 23:09
поделиться

Ну, если бы я столкнулся с этой проблемой, я бы сделал обертку на C++/CLI, только я бы создал специализированный код для того, чего я хочу достичь. В конце концов, со временем я разработаю обертку для общих вещей, но это просто вариант.

Первый шаг - обернуть только вход и выход Boost::Regex. Создать специализированные функции на C++, которые делают все, что вы хотите, и использовать CLI только для передачи входных данных в код C++, а затем получить результат обратно с помощью CLI. Мне это не кажется слишком сложной работой.

Обновление:

Позвольте мне попытаться прояснить свою точку зрения. Даже если я могу ошибаться, я считаю, что вы не сможете найти ни одной реализации .NET Binary Regex, которую вы могли бы использовать. Поэтому - нравится вам это или нет - вы будете вынуждены выбирать между CLI-оберткой и преобразованием байтов в символы для использования .NET's Regex. На мой взгляд, обертка - лучший выбор, потому что она будет работать быстрее. Я не проводил никаких сравнительных тестов, это просто предположение, основанное на следующем:

  1. Используя обертку, вы просто должны привести тип указателя (байты <-> символы).
  2. Используя .NET's Regex, вы должны преобразовывать каждый байт входных данных.
2
ответ дан 30 November 2019 в 23:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: