Регулярное выражение Java на резьбе JPG - PullRequest
0 голосов
/ 16 июля 2011

У меня несколько проблем с использованием регулярных выражений в Java. Я пытаюсь найти файл ISO и вырезать любые изображения JPG, если они там есть.

В настоящее время у меня есть успех с поиском EXIF-информации в JPG, используя следующее регулярное выражение:

Pattern imageRegex = Pattern.compile("\\x45\\x78\\x69\\x66"); //Exif regex

Это работает нормально, и я могу затем отправить в файл EXIF ​​информацию.

Однако, если я использую это регулярное выражение:

Pattern imageRegex = Pattern.compile("\\xff\\xd8\\xff"); //JPG header regex

Java не может найти совпадений. Я могу подтвердить, что в файле ISO есть JPG.

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

Может кто-нибудь посоветовать, почему это происходит, поскольку это довольно запутанно.

Или кто-нибудь может посоветовать лучший способ решения проблемы JPG с разделением файлов с использованием регулярных выражений в Java?

Любой совет будет принят с благодарностью.

Ответы [ 3 ]

0 голосов
/ 16 июля 2011

Если вы читаете в байтовом массиве и конвертируете его в строку, вполне возможно, что проблемы кодирования строк кусают вас сзади. Бывает, что искомый шаблон EXIF ​​полностью совместим с ASCII:

0x45 0x78 0x69 0x66
E    x    i    f

но заголовок JPEG не:

0xff 0xd8 0xff

Вы бы хорошо следовали советам Якуба и пропускали регулярные выражения.

0 голосов
/ 16 июля 2011

Использование регулярных выражений для сопоставления двоичных последовательностей редко уместно; Интересно, хорошо ли вы осведомлены о концептуальных различиях между двоичными данными и строками в Java (в отличие, скажем, от C).

Файл JPEG представляет собой двоичные данные (последовательность байтов ), для использования в регулярном выражении шаблона его необходимо иметь в Java в виде строки (последовательность символов ), это принципиально разные сущности, и для преобразования из одной в другую необходимо указать кодировку кодировки. Кроме того, когда вы указываете литерал \x45 внутри шаблона или в виде буквенной строки, вы не имеете в виду (как вы, кажется, полагаете) «байт с двоичным значением 0x45» (это не имеет смысла, потому что мы не имеем дело с байтами) но, "номер точки символа 0x45 в Юникоде".

Это правда, что в нескольких обычных кодировках (в частности, в UTF-8 и в ISO-8859-1 и его вариантах) последовательность байтов в «диапазоне ASCII» (менее 127) будет преобразована в кодовую точку с этим байтовым значением. Но для других кодировок (как UTF-16) или других значений (в диапазоне 128-255) это не обязательно верно. В частности, это не так для UTF-8 - это справедливо для ISO-8859-1, но вы не должны полагаться на это «совпадение» (если вы это совпадение).

В вашем сценарии я бы сказал, что если вы укажете кодировку ISO-8859-1, вы, вероятно, получите то, что ожидаете. Но все равно будет плохо пахнуть.

Упражнение: попытайтесь предсказать / понять, что печатает этот код:

public static void main(String[] args) throws Exception {
    byte[] b = { 0x30, (byte) 0xb2 };
    String x = new String(b, "ISO-8859-1");
    System.out.println(x.matches(".*\\x30.*"));
    System.out.println(x.matches(".*\\xb2.*"));
    String x2 = new String(b, "UTF-8");
    System.out.println(x2.matches(".*\\x30.*"));
    System.out.println(x2.matches(".*\\xb2.*"));
}

Наведите указатель мыши внизу, чтобы увидеть ответ.

0 голосов
/ 16 июля 2011

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

Может быть, все заголовки JPEG разделены по границам N * 200.

В любом случае, это довольно нетрадиционный (и неэффективный) способ поиска двоичных данных. Почему бы вам не пройти через входной поток , пока не найдете заголовок?

...