LINUX.ORG.RU

Запутался то ли с выводом строки в Си, то ли даже просто с массивом и указателями

 


0

3

Что не так в этом куске кода, никак не пойму. Короткая программка должна тупо вырезать любые xml-теги из входного файла. Просто убирая все теговое, начиная с символа скобка влево и заканчивая скобка вправо.

Если символы не убирать, а заменять, то все нормально, алгоритм работает и на выходе тот же текст, но с забитыми символами на месте тегов. Если убирать (не копированием из одного буфера в другой), то возникают глюки. Часть символов почему-то не копируется.

Проблема тупо в косяке с указателями и длиной буфера? Или с функцией fputs, хотя ее замена на write ничего не дает. Чистка выходного буфера memset тоже ничего не меняет.

Программа открывает файл, читает его функцией read в входной буфер, затем в функции copybuf вырезает теги и копирует то, что без них. Вырезание тегов сделано тупо автоматом с флагом-глобальной переменной tagstatus. Если 0 - символы копируем, если 1 - не копируем, пока не встретим закрывающую угловую скобку.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define BSIZE	64

int copybuf(int bufsize, char* input, char* output);
int tagstatus;

int main(int argc, char** argv)
{
  /* set buffer */
  ssize_t readlen; // bytes
  char inputbuffer[BSIZE+1];
  char outputbuffer[BSIZE+1];
  
  /* Open file */
  int f = open (argv[1],O_NOATIME|O_RDONLY);
  if (f<0)
  {
     fprintf(stderr, "buf: Cannot open file '%s'\n",argv[1]);
     return 1;
  }

  /* read file */
  tagstatus=0;
  while ((readlen = read (f, inputbuffer, BSIZE)) > 0)
  {
       int len=copybuf(readlen,inputbuffer,outputbuffer);      
       if (len>0)
       {
         outputbuffer[len]=0;
         fputs (outputbuffer, stdout);       
       }     
  }

  if (readlen < 0)
  {
    fprintf (stderr, "buf: Cannot read file\n");
    close(f);
    return 1;
  }

  close(f);
  return 0;
}

/* copybuf function */
int copybuf(int bufsize, char* input, char* output)
{
  /* return count of really copied bytes */
  int len=0;
  for (int i=0; i<bufsize; i++)
  {  
     if (tagstatus==0) //outside a tag, main text
     {
        if (input[i]!='<') //no start tag
         {
           output[i]=input[i];len++;
           continue;
         }
         else 
         {
           tagstatus=1;//new tag start            
           continue;
         }
     }
     else //inside a tag
     {
         if (input[i]=='>') //end tag
         {
           tagstatus=0;//close tag
           continue;
         }         
     }
  }
  return len;
}
★★★★★

Ответ на: комментарий от cherry_boy

Кстати да. Но в принципе какого-то только невалидного дерьма нет среди fb2 в архивах. Причем не только по схеме невалидного, но даже не well-formed иногда.

praseodim ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Руками писать что-то не имеет смысла, используя мусорные read/write.

Царь, доработай, пожалуйста, свою программу, чтобы могла работать с stdin. Я хочу написать еще приложение и сделать конвейер а-ля

cat file.xml | remove_tags | replace_escaped

cherry_boy
()
Ответ на: комментарий от cherry_boy

пайпы для анскилльных любителей скриптухи, серьёзный софт использует шаренную память

anonymous
()
Ответ на: комментарий от Virtuos86

Очередной слив растомана. Ты поддержал анонимуса что в расте есть какие-то волшебные строки. А потом выяснилось, что такие же строки есть во многих других языках и приплетать раст тут было неуместно вообще никак. Но надо отдать должное что ты хотя бы признал наполовину свой косяк.

anonymous
()
Ответ на: комментарий от anonymous

серьёзный софт использует шаренную бесконечную память

anonymous
()
Ответ на: комментарий от anonymous

Не только. Он кукарекал не только о волшебных строках, но и об отсутствии индексов. Его послали показывать - он обгадился, позвал мамку и убежал в слезах из треда.

anonymous
()
Ответ на: комментарий от anonymous

Жизнь без пайпов – жизнь на смарку.

anonymous
()
Ответ на: комментарий от anonymous

Привет, опять медсестра укольчик сделать забыла?

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Ну так ты не делай бессознательные комментарии в стиле «в расте есть строки». К чему ты этого безграмотного анонимуса поддержал? Естественно, тебе нечего возразить и ты не можешь ничего прокомментировать. Офигеть, в расте есть строки! Чудеса прямо.

anonymous
()
Ответ на: комментарий от anonymous

В Rust есть что-то типа malloc?

Есть Box аналог std::make_unique из С++, malloc сишный доступен в unsafe.

anonymous
()
Ответ на: комментарий от anonymous

КО-КО-КО НЕ НУЖНО

Обычный юзкейс для прикладного софта, которым является и эта утилита.
Нельзя такое? Ну ладно, я подозревал, что будет такой ответ. :)

cherry_boy
()

А кодировка у входного файла какая? UTF-8 ?

Einstok_Fair ★★☆
()
Ответ на: комментарий от praseodim

python бери. Си упорешься нормализацию слов делать. Скорости хватит. Ну потарахтит месяц, ты дольше писать будешь.

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
$ w3m -dump -cols 130 -s -T text/html -I windows-1251 -O utf-8 Михаил\ Заборов\ -\ Крестоносцы\ на\ Востоке\ \(1980\,\ Наука\).fb2 | head -n 30
sci_history Михаил Заборов Абрамович Крестоносцы на Востоке ru rusec lib_at_rus.ec LibRusEc kit 2007-06-12 Tue Jun 12 12:39:10
2007 1.0

Михаил Абрамович Заборов
                                                                                                                                                  КРЕСТОНОСЦЫ НА ВОСТОКЕ
                                                                                                                                                  Карты Первого Крестового похода

и Крестовых походов XII-XIII вв. - каталог MAPS

ОГЛАВЛЕНИЕ

ОТ СОСИСКИНА, ВЫПОЛНИВШЕГО OCR И КОРРЕКТУРУ

1. ВОЗНИКНОВЕНИЕ КРЕСТОВЫХ ПОХОДОВ

1.1. Смутные времена

1.2. Клюни и рыцарская агрессия

1.3. Византия, Запад и сельджуки

2. ПЕРВЫЙ КРЕСТОВЫЙ ПОХОД                                                                                                                         
2.1. Призыв к войне и отклики на него. Формирование идеологии крестового похода                                                                   
2.2. Поход бедноты
                                                                                                                                                  2.3. Начало похода рыцарства
$
anonymous
()
Ответ на: комментарий от anonymous

Спасибо, интересная возможность, даже не знал, что w3m можно использовать.

Но все же w3m и существенно медленнее даже без mmap получается. А главное, не может слишком большой файл обработать. Например, если 11G подсунуть валится с ошибкой «Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS» Aborted

fbclean.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define BUFFER_SIZE	64

size_t cleanbuf(ssize_t bufsize, char* buf);
int tagstatus;
int gettagstatus(void);
void settagstatus(int newtagstatus);

int main(int argc, char** argv)
{
  /* set buffer */
  ssize_t read_bytes;
  char inputbuffer[BUFFER_SIZE+1];
  char outputbuffer[BUFFER_SIZE+1];
  

  /* check arguments */
  if(argc != 2)
  {
    fprintf(stderr,"Usage: fbclean  fbfile.fb2 \n");
    return 0;
  }

  /* Open fb2 */
  int f = open (argv[1],O_NOATIME|O_RDONLY);
  if (f<0)
  {
     fprintf(stderr, "fbclean: Cannot open file '%s'\n",argv[1]);
     return 1;
  }

  /* read buffer */
  settagstatus(0);//No tags
  while ((read_bytes = read (f, inputbuffer, BUFFER_SIZE)) > 0)
  {
       memset(outputbuffer,0,BUFFER_SIZE);
       int len=cleanbuf(read_bytes,inputbuffer);
       if (len>0)
       {
         inputbuffer[len]=0;/* Add null-terminator for C-string */
         fputs(inputbuffer,stdout);
       }
     
  }

  if (read_bytes < 0)
  {
    fprintf (stderr, "myread: Cannot read file\n");
    return 1;
  }

  close(f);
  return 0;
}

/* cleanbuf function */
size_t cleanbuf(ssize_t bufsize, char* buf)
{
  /* return count of really copied bytes */

  /* copy from buf to output=buf if need */
  char *output=buf, *beg0=buf;buf--; //buf-- for start cycle
  while ((++buf-beg0)<bufsize) 
  {  
     if (gettagstatus()==0) //outside a tag, main text
     {
        if (*buf!='<') //no start tag
         {
           *output++=*buf;
           continue;
         }
         else 
         {
           settagstatus(1);//new tag start
           continue;
         }
     }
     else //inside a tag
     {
         if (*buf=='>') //end tag
         {
           settagstatus(0);//close tag             
           continue;
         }
         else
         {
           continue;
         }
     }
  } //for
  return output-beg0;
}

/* tagstatus functions */
int gettagstatus(void)
{
  return tagstatus;
}
void settagstatus(int newtagstatus)
{ 
  tagstatus=newtagstatus;
  return;
}

Делаем тестовый пример, где-то на 10Гб, просто копируя исходный файл

create-test.sh

#!/bin/bash
for ((i=1; i<=10000; i++))
do
cat $1 >> $2
done

Тестируем.

$ time ./fbclean 1.fb2 > /dev/null

real	0m47.431s
user	0m16.348s
sys	0m31.060s

$ time w3m -dump -cols 130 -s -T text/html 1.fb2 > /dev/null
Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS
Aborted

real	1m43.151s
user	5m58.757s
sys	0m4.496s

Я правда не уверен, что такие большие файлы встретятся, это просто тест, но все же.

praseodim ★★★★★
() автор топика
Последнее исправление: praseodim (всего исправлений: 1)

Не читал весь тред, тебе надо поставить валгринд. При странных ошибках запускаешь через него и он показывает тебе где косяк. Еще надо юниттесты писать. За запуск юниттестов под валгриндом дадут бонусные очки.

anonymous
()
Ответ на: комментарий от praseodim

sax-парсер тебе нужен. есть два вида парсеров хмл: дом который загружает весь документ в память, и сакс - он не загружает всё в память, а реализует состояния с обратными вызовами. либо можешь сделать сам: когда встречаешь < включаешь игнор, когда встречаешь > - выключаешь. это всё. не забудь про непарные скобки.

anonymous
()
Ответ на: комментарий от praseodim

Но ведь нет книг на 11Gb. Просто не подсовывай такое и всё.

anonymous
()
Ответ на: комментарий от praseodim

Без -cols -s пробовал? Может он там строки клеит.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.