2015-04-13 2 views
2

Мне нужно поведение по умолчанию (например, ENT_COMPAT | ENT_HTML401) PHP-функции htmlspecialchars() в C, как это делается лучше всего (что означает самый быстрый) в C?Быстрая повторная реализация функции htmlspecialchars PHP в C

Мне не нужна входная строка, поэтому возможно решение на месте.

Это очень простая функция, он просто преобразует эти символы:

'&' -> '&' 
'"' -> '"' 
'<' -> '&lt;' 
'>' -> '&gt;' 

Какая стратегия была бы быстрее? Зацикливание каждого символа в отдельности и создание выходного буфера по байтам, переписывание входной строки на месте или какое-либо другое решение?

+0

Выделяют выход с два раза размер вашего ввода, а затем при необходимости измените его размер. –

+0

Кроме того, вы можете просто проверить фактическую [реализацию] (http://lxr.php.net/xref/PHP_5_6/ext/standard/html.c#1226) этой функции php. –

+0

Самая быстрая реализация зависит от типичных входных характеристик. Является ли ваш типичный ввод несколькими частями символов или документами размером с гигабайт? Как часто кодируются объекты? У вас есть ограничения памяти? –

ответ

1

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

long i = 0; 
long j = 0; 

while (input[i]) 
{ 
    if (input[i] == '<') 
    { 
     memcpy(&output[j], "&lt;", 4); 
     j += 4; 
    } else if (input[i] == '>') 
    { 
     memcpy(&output[j], "&gt;", 4); 
     j += 4; 
    } else if (input[i] == '"') 
    { 
     memcpy(&output[j], "&quot;", 6); 
     j += 6; 
    } else if (input[i] == '&') 
    { 
     memcpy(&output[j], "&amp;", 5); 
     j += 5; 
    } else 
    { 
     output[j++] = input[i]; 
    } 
    if (j > sizeof(output)-7) 
    { 
     break; 
    } 
    i++; 
} 
output[j] = 0; 

В C, уродливый код часто самый быстрый.

Решение на месте может привести только к преимуществам производительности, если символы, подлежащие обмену, будут очень и очень редкими, так что вся строка может быть переупорядочена (очень дорого) для каждого обнаруженного символа. С обычными HTML-данными, где эти 4 символа появятся часто, решение на месте будет намного медленнее.

+1

Сколько памяти вы бы выделили для 'output'? – hek2mgl

+0

@ hek2mgl: Если функция используется по назначению (для данных в формате HTML), то в два раза больше памяти на входе должно быть много. Но спасибо за комментарий, я удалю этот яркий буфер, переполненный в этом коде! –

+0

Нет проблем. Я просто спрашивал. Поскольку комментарий из [@Jack] (http://stackoverflow.com/questions/29599597/fastest-reimplementation-phps-htmlspecialchars-function-in-c#comment47345814_29599597) был интересным. – hek2mgl

1

Вы можете построить решение, которое работает в обоих случаях:

Вычисляет необходимое пространство и возвращать выделенные строки, когда NULL передается, в противном случае заполнить переданную строку:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

static size_t encode_len(const char *str) 
{ 
    size_t len = 0; 

    while (*str) { 
     if (*str == '"' || *str == '&' || *str == '<' || *str == '>') { 
      len += 5; 
     } else { 
      len += 1; 
     } 
     str++; 
    } 
    return len; 
} 

static char *encode(const char *str, char *dest) 
{ 
    char *ptr; 

    if (dest == NULL) { 
     dest = malloc(encode_len(str) + 1); 
     if (dest == NULL) return NULL; 
    } 
    ptr = dest; 
    while (*str) { 
     switch (*str) { 
      case '"': memcpy(ptr, "&#34;", 5); ptr += 5; break; 
      case '&': memcpy(ptr, "&#38;", 5); ptr += 5; break; 
      case '<': memcpy(ptr, "&#60;", 5); ptr += 5; break; 
      case '>': memcpy(ptr, "&#62;", 5); ptr += 5; break; 
      default: *ptr++ = *str; 
     } 
     str++; 
    } 
    *ptr = *str; 
    return dest; 
} 

int main(void) 
{ 
    /* Returns an allocated string */ 
    char *str = encode("testing & <> \"", NULL); 
    if (str) { 
     printf("%s\n", str); 
     free(str); 
    } 

    /* Fills a passed string */ 
    char str2[128]; 
    encode("testing & <> \"", str2); 
    printf("%s\n", str2); 

    return 0; 
} 
+0

Вы бы использовали функцию encode_len даже в реальном мире? Не лучше ли было бы дать * хорошую оценку *, возможно, в два раза больше размера ввода и выделить больше, если вам нужно больше? Я просто спрашиваю ... – hek2mgl

+1

@ hek2mgl, это хорошая вещь в динамической памяти, вам не стоит беспокоиться о длине строки (просто потребляйте то, что вам нужно). –

+0

В этом конкретном прецеденте (HTML обычно поставляется в довольно небольших фрагментах, а не в гигабайтах данных), вы также можете просто зарезервировать 6 раз от длины ввода и быть намного быстрее, чем пытаться выжать каждый байт. –

Смежные вопросы