2

C ソース コードから文字列を削除するプログラムを教えてもらえますか? 例

#include <stdio.h>
static const char *place = "world";
char * multiline_str = "one \
two \
three\n";
int main(int argc, char *argv[])
{
        printf("Hello %s\n", place);
        printf("The previous line says \"Hello %s\"\n", place);
        return 0;
}

になる

#include <stdio.h>
static const char *place = ;
char * multiline_str = ;
int main(int argc, char *argv[])
{
        printf(, place);
        printf(, place);
        return 0;
}

私が探しているのは、stripcmtに非常によく似たプログラム で、コメントではなく文字列を削除したいだけです。

便利な正規表現だけでなく、既に開発されたプログラムを探している理由は、すべてのコーナーケース (文字列内の引用符、複数行の文字列など) を検討し始めると、通常、それよりも (はるかに) 複雑になり始めるためです。初登場。また、RE が達成できることには限界があります。このタスクでは不可能だと思います。非常に堅牢な正規表現を持っていると思われる場合は、お気軽に送信してください。ただし、素朴sed 's/"[^"]*"//g'な提案はご遠慮ください。

(コメント内の(おそらく終了していない)文字列を特別に処理する必要はありません。それらは最初に削除されます)

改行が埋め込まれた複数行の文字列のサポートは重要ではありませんが (正当な C ではありません)、末尾が \ で終わる複数行にわたる文字列はサポートされなければなりません。

これは他のいくつかの 質問とほぼ同じですが、ツールへの参照は見つかりませんでした。

4

4 に答える 4

5

C (および他のほとんどのプログラミング言語) のすべてのトークンは「正規」です。つまり、正規表現で一致させることができます。

C 文字列の正規表現:

"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"

正規表現を理解するのはそれほど難しくありません。基本的に、文字列リテラルは、次のものを囲む二重引用符のペアです。

  • 非特殊 (非引用符/バックスラッシュ/改行) 文字
  • バックスラッシュで始まり、次のいずれかで構成されるエスケープ。
    • 単純なエスケープ文字
    • 1 桁から 3 桁の 8 進数
    • x と 1 つ以上の 16 進数

これは、C89/C90 仕様のセクション 6.1.4 および 6.1.3.4 に基づいています。C99 に他の何かが忍び寄った場合、これはそれをキャッチしませんが、修正するのは難しくありません。

文字列リテラルを削除して C ソース ファイルをフィルタリングする Python スクリプトを次に示します。

import re, sys
regex = re.compile(r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"''')
for line in sys.stdin:
  print regex.sub('', line.rstrip('\n'))

編集:

上記を投稿した後、すべての C トークンが規則的であることは事実ですが、すべてをトークン化しないことで問題が発生する可能性があることに気付きました。特に、別のトークンであるべきところに二重引用符が表示された場合、庭の小道をたどることができます。コメントは既に削除されているとおっしゃいましたが、他に本当に気にする必要があるのは文字リテラルだけです (ただし、これから使用するアプローチは、コメントを処理するように簡単に拡張できます)。文字リテラルを処理するより堅牢なスクリプトを次に示します。

import re, sys
str_re = r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"'''
chr_re = r"""'([^'\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))'"""

regex = re.compile('|'.join([str_re, chr_re]))

def repl(m):
  m = m.group(0)
  if m.startswith("'"):
    return m
  else:
    return ''
for line in sys.stdin:
  print regex.sub(repl, line.rstrip('\n'))

基本的に、文字列と文字リテラルのトークンを見つけてから、char リテラルをそのままにして、文字列リテラルを取り除きます。char リテラルの正規表現は、文字列リテラルの正規表現と非常によく似ています。

于 2009-08-18T15:32:25.313 に答える
4

ソースコードは StripCmt (.tar.gz - 5kB)にダウンロードできます。それは自明なほど小さく、代わりに文字列のストライピングに適応するのはそれほど難しくありません ( GPL の下でリリースされています)。

また、C 文字列の公式の字句言語規則を調査することもできます。これはすぐに見つかりましたが、決定的なものではないかもしれません。文字列を次のように定義します。

stringcon ::= "{ch}", where ch denotes any printable ASCII character (as specified by isprint()) other than " (double quotes) and the newline character.
于 2009-08-18T15:02:35.610 に答える
0

ルビーで:

#!/usr/bin/ruby
f=open(ARGV[0],"r")
s=f.read
puts(s.gsub(/"(\\(.|\n)|[^\\"\n])*"/,""))
f.close

標準出力に出力します

于 2009-08-18T16:28:13.173 に答える
0

Python で pyparsing を使用する場合:

from pyparsing import dblQuotedString

source = open(filename).read()
dblQuotedString.setParseAction(lambda : "")
print dblQuotedString.transformString(source)

stdout にも出力します。

于 2009-09-04T16:47:48.430 に答える