Вставьте недостающие запятые в источник C

У меня есть perl-скрипт (использующий флаг -p), который выполняет некоторые исправления в поврежденном исходном файле C. Вот часть скрипта:

sub remove_sp {
    $_ = shift; 
    s/ /, /g; 
    return $_;
}

s/(\([^}]*\))/remove_sp($1)/eg;

Это заменяет пробелы внутри круглых скобок на , например. foo(bar baz) становится foo(bar, baz). Однако это не очень умно. Он также изменяет foo("bar baz") на foo("bar, baz"), что, очевидно, не то, что мне нужно.

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


Вот простая таблица того, что мне нужно и что не работает.

Search                       | Replace                        | Currently handled correctly?
--------------------------------------------------------------------------------------------
foo(bar baz)                 | foo(bar, baz)                  | Yes
foo("bar baz")               | foo("bar baz")                 | No
foo("bar baz" bak)           | foo("bar baz", bak)            | No
foo("bar baz" bak "123 abc") | foo("bar baz", bak, "123 abc") | No

person MD XF    schedule 28.02.2018    source источник
comment
@MattJacob Проблема связана с вводом, таким как print("foo bar" baz), который должен получиться как print("foo bar", baz).   -  person MD XF    schedule 28.02.2018
comment
Совет: не забивайте $_!!! По крайней мере, используйте local $_ = shift;, но даже это может вызвать проблемы, потому что $_ нередко ассоциируется с магической или доступной только для чтения переменной. for (my $s = shift) { ... } безопасен, но в большинстве случаев лучше использовать только my $s = shift;.   -  person ikegami    schedule 28.02.2018


Ответы (2)


Вы можете использовать Text::ParseWords, чтобы получить данные между скобками и выполнить замену результатов синтаксического анализа.

#!/usr/bin/perl
use strict;
use warnings;
use Text::ParseWords;

for ('foo("bar baz")', 'print("foo bar" baz)', 'foo(bar baz)') {
    my $s = $_;
    $s =~ s/(\([^)]*\))/remove_sp($1)/eg;
    print $s, $/;
}

sub remove_sp {
    join ", ", quotewords('\s+', 1, shift);
}

Выход:

foo("bar baz")
print("foo bar", baz)
foo(bar, baz)
person Chris Charley    schedule 28.02.2018

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

Вставка строк

foo("abc" "def");   // = foo("abcdef")
foo("foo", "bar");

Размещение двух строковых констант рядом друг с другом приводит к их "вставке" вместе. Не зная, сколько аргументов требуется для функции, невозможно сказать, было ли это ожидаемым поведением.

Выражения с запятыми, например. в for петель

Запятая — это оператор в C; он оценивает два выражения и возвращает значение того из них, которое находится справа. В сочетании с унарной/бинарной двойной природой операторов +, -, & и * это означает, что такое простое выражение, как:

a + b    or    a * b

можно поставить запятую:

a, +b    or    a, *b

Хотя это надуманный пример, могут возникнуть и более сложные случаи, например. в сложных for петлях.

Аргументы функции

Сходным образом:

foo(a * b - 1);
foo(a * b, -1);
foo(a, *b - 1);
foo(a, *b, -1);
(etc)

Не зная количества аргументов, ожидаемых от функции, невозможно определить, следует ли ставить запятую. А иногда и этого недостаточно!

person Community    schedule 28.02.2018
comment
Я не искал оптимальную коррекцию/сжатие синтаксиса C, просто добавлял запятые там, где это необходимо. Мы можем предположить, что везде, где запятая выглядит так, как будто она должна существовать, она должна существовать. - person MD XF; 28.02.2018
comment
Дело не в исправлении/сжатии. Бывают ситуации, когда невозможно сказать, должна ли стоять запятая или нет. Если бы можно было угадать, где должны быть все запятые, вам не нужно было бы их ставить. :) - person ; 28.02.2018
comment
Я просто говорю, что этот ответ выходит за рамки вопроса; Я хочу заменить пробелы между скобками на запятую, если пробелы не находятся между кавычками. - person MD XF; 01.03.2018