LINUX.ORG.RU

коментарии после кода в строке поместить в новую строку над

 , ,


1

1

это

    код // есть ли готовые инструменты для такого?

нужно в это

    // есть ли готовые инструменты для такого?
    код 


Последнее исправление: naKovoNapalBaran (всего исправлений: 2)

Заменить // на \n//?
В одном файле: любой текстовый редактор.
В проекте: регулярка на любимом ЯП.

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

Вот тебе готовый инструмент.

По хорошему надо ещё доработать правильную обработку EINTR и ошибок и динамический размер буфера под строку, но вообще будет работать и так в 99.999% случаев. Сейчас при обнаружении строки длиннее MAX_LINE_LEN символов с //-комментарием результат будет молча некорректный (если без комментария - всё норм). А также при столкновении с например ошибкой чтения с диска прога не выдаст никаких варнингов а просто сделает вид что на этом месте закончился входной файл.

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

static void handle_line(char *b, char const *eoln, char const *def_eoln);
int main(void) {
#define MAX_LINE_LEN 100000
  static char b[MAX_LINE_LEN];

  char * p;
  char const *eoln, *def_eoln;
  def_eoln = "\n";
  while(fgets(b,sizeof(b),stdin)) {
    p = strchr(b,'\n');
    if(p) {
      assert(!p[1]);
      if(p!=b && *(p-1)=='\r') { eoln = "\r\n"; *(p-1) = 0; }
      else { eoln = "\n"; *p = 0; }
      def_eoln = eoln;
    } else eoln = "";
    handle_line(b, eoln, def_eoln);
  }
  return 0;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln) {
  size_t p, plen;
  char c, q;
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = 0;
  while(c = b[p]) {
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c!='/' || b[p+1]!='/') { p++; continue; }
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  fputs(b, stdout); fputs(eoln, stdout);
}

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Зачем так сложно?

#include <stdio.h>
#include <ctype.h>

#define BUFLEN 10000

int main(void)
{
        char buf[BUFLEN];
        while (fgets(buf, BUFLEN, stdin)) {
                int i, nsp;
                for (nsp = 0; isspace(buf[nsp]); nsp++);
                for (i = nsp; buf[i] != '\0'; i++) {
                        if (buf[i] == '/' && buf[i + 1] == '/') {
                                fwrite(buf, nsp, 1, stdout);
                                printf("%s", buf + i);
                                buf[i] = '\n';
                                buf[i + 1] = '\0';
                                break;
                        }
                }
                printf("%s", buf);
        }
        return 0;
}
mrn
()
Ответ на: комментарий от mrn

А ты посмотри в чём разница и поймёшь какого функционала не хватает в твоём коде. Хотя автор этого и не просил, но я почти уверен, что строку

   printf("some // text // literal");
не надо превращать в
   // text // literal");
   printf("some

Ну и твой код не поддерживает файлы с \r\n-окончаниями строк, будет вставлять в них комменты с \n (без \r) на конце.

А ещё твой код выведет мусор если на входе будет последняя строка с комментом и без \n в конце.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 4)

пытался так, но они
в один отступ выравнивают коментарии

sed 's:^\([[:space:]]\)\(.*\)\(\/\/.*\)$:\1\3\n\1\2:'
sed 's:^\(\([[:space:]]\).*\)\(\/\/.*\)$:\2\3\n\1:'
naKovoNapalBaran
() автор топика
Ответ на: комментарий от firkax

Да, ты прав.

Кавычки и конец файла исправляются в пару строк:

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

#define BUFLEN 10000

int main(void)
{
        char buf[BUFLEN];
        while (fgets(buf, BUFLEN, stdin)) {
                int i, nsp, nq = 0;
                for (nsp = 0; isspace(buf[nsp]); nsp++);
                for (i = nsp; buf[i] != '\0'; i++) {
                        if (buf[i] == '"')
                                nq++;
                        if (nq % 2 == 0 && buf[i] == '/' && buf[i + 1] == '/') {
                                char *const cm = buf + i;
                                fwrite(buf, nsp, 1, stdout);
                                printf("%s", cm);
                                if (cm[strlen(cm) - 1] != '\n')
                                        printf("\n");
                                buf[i] = '\n';
                                buf[i + 1] = '\0';
                                break;
                        }
                }
                printf("%s", buf);
        }
        return 0;
}

Про \r\n думать лень, и так громоздко получилось.

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

Ну ты издеваешься?

Во-первых, одинарные кавычки тоже надо учитывать, даже в Си конструкция '//qq' вполне валидна, по крайней мере в большинстве компиляторов, не говоря уже про всякие пхп (а автор не сказал для какого языка ему конвертор). Во-вторых,

  printf("some\" // literal"); // q

надо превратить в

  // q
  printf("some\" // literal");
а не в
  // literal"); // q
  printf("some\"
как сделает твой код.

Про \r\n думать лень, и так громоздко получилось.

Ну естественно.

Зачем так сложно?

Потому и сложно, что я всё продумал сразу (и указал сразу же полный список того, что не реализовано и может вызвать проблемы) а ты дописываешь фиксы по факту принятых замечаний (bug-driven development). Хотя на самом деле даже это намного приятнее видеть чем всякие sed или php.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от naKovoNapalBaran
$ echo "    код // есть ли готовые инструменты для такого?" | sed 's:^\([[:space:]]*\)\(.*\)\(\/\/.*\)$:\1\3\n\1\2:'
    // есть ли готовые инструменты для такого?
    код 
xaizek ★★★★★
()
Ответ на: комментарий от i-rinat

Ай, виноват да. Многострочные комменты упустил. :( Впрочем, у меня есть оправданиеотмаза - автор ставил задачу по построчной конвертации, а в её рамках их полноценно учесть невозможно.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Вот вариант с многострочными комментами и заодно варнингами про проблемный синтаксис и ошибки чтения:

/* (c) firk; may use without restrictions */
#include <stdio.h>
#include <assert.h>
#include <string.h>

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq);

int main(int argc, char const * const * argv) {
#define MAX_LINE_LEN 100000
  static char b[MAX_LINE_LEN];
  char q;
  unsigned long ln;
  int warnq;
  char * p;
  char const *eoln, *def_eoln;
  
  warnq = !(argc>=2 && !strcmp(argv[1],"--multistring"));
  def_eoln = "\n";
  q = 0;
  ln = 0;
  while(fgets(b,sizeof(b),stdin)) {
    ln++;
    p = strchr(b,'\n');
    if(p) {
      assert(!p[1]);
      if(p!=b && *(p-1)=='\r') { eoln = "\r\n"; *(p-1) = 0; }
      else { eoln = "\n"; *p = 0; }
      def_eoln = eoln;
    } else eoln = "";
    handle_line(b, eoln, def_eoln, &q, ln, warnq);
  }
  if(ferror(stdin)) fprintf(stderr, "error reading input (last read line is %lu)\n", ln);
  if(q=='/') fprintf(stderr, "warning: unterminated multiline comment at EOF (last line is %lu)\n", ln);
  else if(q) fprintf(stderr, "warning: unterminated quoted (%c) entity at EOF (last line is %lu)\n", q, ln);
  return 0;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq) {
  size_t p, plen;
  char c, q;
  char q0;
  
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = q0 = *pq;
  while(c = b[p]) {
    if(q=='/') {
      p++;
      if(c=='*' && b[p]=='/') { p++; q = 0; }
      continue;
    }
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c=='/' && b[p+1]=='*') { q='/'; p+=2; continue; }
    if(c!='/' || b[p+1]!='/') { p++; continue; }
    /* found unquoted // */
    if(q0) {
      if(q0=='/') fprintf(stderr, "warning: can't safely reorder //-comment due to pending multiline-comment at line %lu beginning\n", ln);
      else fprintf(stderr, "warning: can't safely reorder //-comment due to pending quoted (%c) entity at line %lu beginning\n", q, ln);
      break;
    }
    /* here q0==0 && q==0 */
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  /* found EOLN w/o // */
  fputs(b, stdout); fputs(eoln, stdout);
  *pq = q;
  if(warnq && q && q!='/') fprintf(stderr, "warning: unterminated quoted (%c) entity at line %lu\n", q, ln);
}

Строки длиннее MAX_LINE_LEN с комментами всё так же молча дают неверный реультат (а со строками - лишние варнинги, но верный результат).

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

Я с некоторых пор вообще //-комментами не пользуюсь, а пока пользовался - вполне удобная конструкция. Причём это не обязательно коммент в комменте (что тоже бывает), второе // может быть просто визуальным разделителем частей комментария.

firkax ★★★★★
()
Ответ на: комментарий от i-rinat

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

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

тем более такой редкий и странный случай с двумя //

mumpster ★★★★★
()
Ответ на: комментарий от i-rinat

действительно, работает. но вообще-то это некорректная работа анализатора, он должен дать ошибку

скорее всего это стало работать с извращенского C99

mumpster ★★★★★
()
sed -e 's/\(.*\)\(\/\/.*\)/\2\n\1/g'

Хотя соглашусть, что покрыть все случаи тут сложновато, единственное, что могу посоветовать из +- универсальных решений, так это clang-format для Си/Си++, который очевидно контектстно чувствителен, хотя не уверен прописана ли в нём возможность такого переформатирования, с другой стороны можете написать самостоятельно подобный парсер, т.к. контекстных случаев в которых это не ОК - не так уж много, либо вместо парсера просто пройдитесь по исходникам с помощью грепа и ручками подправьте.

AKonia ★★
()
Последнее исправление: AKonia (всего исправлений: 2)
Ответ на: комментарий от naKovoNapalBaran

Этот случай можно подправить:

$ echo "     // есть ли готовые инструменты для такого?" | sed '/^\s*[^ ].*\/\//s:^\([[:space:]]*\)\(.*\)\(\/\/.*\)$:\1\3\n\1\2:'
xaizek ★★★★★
()
Ответ на: комментарий от i-rinat

По-моему проще весь подобный изврат просто логировать как ошибки, ибо он однозначно вреден в любых необфусцированных исходниках. Все предыдущие случаи могли быть вполне реальными и уместными в коде. Но ладно, задача интересная как просто абстрактная теория. Вот:

/* (c) firk; feel free to use for anything */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static char * wise_gets(char const * * eoln_type, unsigned long long * p_ln) {
  static char * buf;
  static size_t bs, bp, bl;
  static unsigned long long ln = 1;
  static int eof;
  size_t csz;
  ssize_t rsz;
  
  if(bp) {
    bl -= bp;
    if(bl) bcopy(buf+bp, buf, bl);
    bp = 0;
  }
  if(eof && !bl) return NULL;
  *p_ln = ln;
  while(1) {
    if(!eof) {
      if(bl==bs) {
        bs += 50 + bs/3;
        if(bs<=bl) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
        if(!buf) buf = malloc(bs); else buf = realloc(buf, bs);
        if(!buf) { fprintf(stderr, "line %llu too long // out of memory\n", ln); exit(-1); }
      }
      csz = bs-bl;
      if(((ssize_t)csz)<=0) csz/=2;
      while((rsz = read(0, buf+bl, csz))<0) if(errno!=EINTR) { fprintf(stderr, "error reading input at line %llu, error %d (%s)\n", ln, errno, strerror(errno)); rsz = 0; break; }
      if(!rsz) eof = 1; else bl += rsz;
    }
    for( ; bp<bl; bp++) {
      if(buf[bp]!='\n') continue;
      ln++;
      if(!bp) { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(buf[bp-1]=='\\') continue;
      if(buf[bp-1]!='\r') { buf[bp++] = 0; *eoln_type = "\n"; return buf; }
      if(bp==1 || buf[bp-2]!='\\') { buf[bp-1] = 0; bp++; *eoln_type = "\r\n"; return buf; }
    }
    if(eof) {
      assert(bl<bs); /* eof results from failed read() so bs-bl>0 */
      buf[bp] = 0; *eoln_type = NULL; return buf;
    }
  }
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq);

int main(int argc, char const * const * argv) {
  char q;
  unsigned long long ln;
  int warnq;
  char *b, *p;
  char const *eoln, *def_eoln;
  
  warnq = !(argc>=2 && !strcmp(argv[1],"--multistring"));
  def_eoln = "\n";
  q = 0;
  while(b=wise_gets(&eoln,&ln)) {
    if(eoln) def_eoln = eoln; else eoln = "";
    handle_line(b, eoln, def_eoln, &q, ln, warnq);
  }
  if(q=='/') fprintf(stderr, "warning: unterminated multiline comment at EOF (last line is %lu)\n", ln);
  else if(q) fprintf(stderr, "warning: unterminated quoted (%c) entity at EOF (last line is %lu)\n", q, ln);
  return 0;
}

static char * skip_eolns(char * b) {
  while(*b=='\\') {
    if(b[1]=='\n') { b+=2; continue; }
    if(b[1]=='\r' && b[2]=='\n') { b+=3; continue; }
    break;
  }
  return b;
}

static void handle_line(char *b, char const *eoln, char const *def_eoln, char *pq, unsigned long ln, int warnq) {
  size_t p, plen;
  char c, q;
  char q0;
  char *bb;
  
  for(p=0; (c=b[p])==' ' || c=='\t'; p++);
  plen = p;
  q = q0 = *pq;
  while(c = b[p]) {
    if(q=='/') {
      p++;
      if(c=='*' && *(bb=skip_eolns(b+p))=='/') { p = (bb-b)+1; q = 0; }
      continue;
    }
    if(q) {
      p++;
      if(c==q) q=0;
      else if(c=='\\') { if(b[p]) p++; }
      continue;
    }
    if(c=='\'' || c=='"') { q=c; p++; continue; }
    if(c=='/' && *(bb=skip_eolns(b+p+1))=='*') { q='/'; p=(bb-b)+1; continue; }
    if(c!='/' || *(bb=skip_eolns(b+p+1))!='/') { p++; continue; }
    /* found unquoted // */
    if(q0) {
      if(q0=='/') fprintf(stderr, "warning: can't safely reorder //-comment due to pending multiline-comment at line %lu beginning\n", ln);
      else fprintf(stderr, "warning: can't safely reorder //-comment due to pending quoted (%c) entity at line %lu beginning\n", q, ln);
      break;
    }
    /* here q0==0 && q==0 */
    if(plen) fwrite(b, 1, plen, stdout);
    fputs(b+p, stdout);
    fputs(def_eoln, stdout);
    while(p && (b[p-1]==' ' || b[p-1]=='\t')) p--;
    if(p) { fwrite(b, 1, p, stdout); fputs(eoln, stdout); }
    return;
  }
  /* found EOLN w/o // */
  fputs(b, stdout); fputs(eoln, stdout);
  *pq = q;
  if(warnq && q && q!='/') fprintf(stderr, "warning: unterminated quoted (%c) entity at line %lu\n", q, ln);
}

Поддерживается \, поддерживаются строки любой длины на какую хватит памяти и нормально обрабатываются все errno из чтения. Правда я бы потестировал этот код на всякий случай на всяких разных данных.

А да, ещё проблема - если на входе встретится \0 то строка с ним будет обрезана на выходе.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Ух, жесть какая получилась.

Не буду тянуть. Вот, что ещё оставалось в запасе.

  • триграфы: \ можно заменить на ??/ и таким образом спрятать от форматтера
  • #include </dev//null> — вполне допустимая конструкция
  • окончание строки может быть не только «\n» и «\r\n», но и «\r» (Mac OS 9, например)
  • обработка \ в конце строки сломается, если в качестве окончания этой конкретной строки будет использовано «\r\r\n»

Ну и я не думаю, что ты будешь спорить с тем, что всё равно всё скатилось в «bug-driven development».

i-rinat ★★★★★
()

Idea: Enter перед комментом, затем Ctrl-Shift-вверх

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

Ну и я не думаю, что ты будешь спорить с тем, что всё равно всё скатилось в «bug-driven development».

Буду, см. ниже в конце поста.

триграфы

Так и думал что с ними какая-нить пакость будет, но забыл что там \ можно закодировать.

#include </dev//null> — вполне допустимая конструкция

Не знал.

окончание строки может быть не только «\n» и «\r\n», но и «\r» (Mac OS 9, например)

Однако большинство редакторов \r за конец строки не считают (и ни одна современная ОС его не использует так). Хотя \n не распознаётся некоторыми виндопрогами (например, блокнотом), но это скорее исключения. Хотя gcc принимает такое, как оказалось.

обработка \ в конце строки сломается, если в качестве окончания этой конкретной строки будет использовано «\r\r\n»

А это вообще нигде не считается концом строки. Это либо конец строки + один или два лишних символа (которые портят эффект от \), либо два конца строки (т.е. пустая строка в середине, тоже нейтрализует \) + один лишний символ после.

всё скатилось в «bug-driven development»

Нет, и вот по каким причинам:

1) когда я выставлял претензию mrn за его слишком простой код, его код ломался на вполне реальных, и при том распространённых случаях, а тут - всякая экзотика, которую на мой взгляд давно пора отвергать с compile error.

2) автор не указал для какого ему языка, его пример мог подходить к чему угодно с си-подобным синтаксисом, а конструкции вида «/\\\n*» или тем более триграфы - это конкретно Си/С++. То же самое касается инклюдов.

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

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

А это вообще нигде не считается концом строки.

Точно, да. Ошибся.

По идее, можно пропатчить GCC так, чтобы он «\r\r\n» принимал за корректное окончание строк, и после этого он всё ещё будет удовлетворять стандарту. Я не нашёл в стандарте требования к виду окончания строк. Но это уже за уши притянуто, да.

тут - всякая экзотика, которую на мой взгляд давно пора отвергать с compile error

Стандарт допускает, значит можно.

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

Ну то есть ты сделал предположение, и начал плясать от него. Но почему-то предположения других людей это bug-driven development, а твои — нет. Это двойные стандарты. Не понимаю, зачем ты это вообще упоминаешь. Этот пункт только разрушает твою позицию, а не подкрепляет её.

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

Там не предположения были а желание упростить код. Причём он потом сам согласился, что упустил важные вещи. Я так до сих пор и не понял зачем он это сделал.

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

Ты не сможешь убедить меня, а я не смогу убедить тебя. Я до сих пор вижу в твоей позиции двойные стандарты. @mrn обновил код, когда ему сообщили о случаях, которые его код не обрабатывает. Ты обновил код, когда тебе сообщили о случаях, которые твой код не обрабатывает. Но почему-то у @mrn — bug-driven development, а у тебя нет.

И вообще, ты говоришь об багфиксах как о чём-то плохом. Баги в коде это данность. Не всегда баги связаны с переполнением буфера. Иногда ошибки состоят просто в самом подходе к проблеме.

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

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

Я ещё раз напомню, что парсер Си я (тут) не писал и писать не собирался. И у mrm тоже не он. Речь шла о парсере неуказанного языка, в котором бывают //-комменты. Я не делал уточняющих предположений о том, что это за язык, и обработал случаи, общие для всех таких языков, но не обрабатывал то, что повысит совместимость с каким-то конкретным, в ущерб универсальности.

mrm же написал «что так сложно» (то есть мотивация - не выбор нужного функционала, а лень в написании кода) и выкинул больше половины кода, а затем добавил его же назад, когда я ему указал что без него всё плохо. Это разные вещи.

firkax ★★★★★
()

pwsh:

PS > gc file.old

code1 // comment1
code2
code3

code4
code5 // comment5
code6

code7
code8 // comment8

PS > & {
   >>    (gc file.old).foreach({
   >>
   >>        if ($_ -match '^.+//')
   >>            { "{1}`n{0}" -f ($_ -split '(?<=^.+\s+)(?=//.+$)') }
   >>        else
   >>            { $_ }
   >>     }) | sc file.new     # sc псевдоним (alias) для Set-Content
   >>  }

PS > gc file.new

// comment1
code1
code2
code3

code4
// comment5
code5
code6

code7
// comment8
code8
anonymous
()
Ответ на: комментарий от naKovoNapalBaran
sed -i '/^\s*[^[:space:]].*\/\//s:^\([[:space:]]*\)\(.*\)\(\/\/.*\)$:\1\3\n\1\2:'

получается

  //
  /

  // here
  printf("some\" // literal"); // comment

нужно

  ///

  // literal"); // comment // here
  printf("some\" 
naKovoNapalBaran
() автор топика
Последнее исправление: naKovoNapalBaran (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.