Regex Awk不';不匹配所有匹配我的所有条目

Regex Awk不';不匹配所有匹配我的所有条目,regex,awk,header-files,text-extraction,Regex,Awk,Header Files,Text Extraction,我试图制作一个“脚本”——本质上是一个awk命令——来提取.C文件中C代码函数的原型,从而自动生成一个header.h。 我是awk的新手,所以我不了解所有细节 这是源代码的一个示例。c: dict_t dictup(dict_t d, const char * key, const char * newval) { int i = dictlook(d, key); if (i == DICT_NOT_FOUND) { fprintf(stderr, "key \"%s\

我试图制作一个“脚本”——本质上是一个awk命令——来提取.C文件中C代码函数的原型,从而自动生成一个header.h。 我是awk的新手,所以我不了解所有细节

这是源代码的一个示例。c:

dict_t dictup(dict_t d, const char * key, const char * newval)
{

  int i = dictlook(d, key);

  if (i == DICT_NOT_FOUND) {

    fprintf(stderr, "key \"%s\" doesn't exist.\n", key);
    dictdump(d);
  }
  else {

    strncpy(d.entry[i].val, newval, DICTENT_VALLENGTH);
  }

  return d;
}


dict_t* dictrm(dict_t* d, const char * key) {

  int i = dictlook(d, key);

  if (i == DICT_NOT_FOUND) {

    fprintf(stderr, "key \"%s\" doesn't exist.\n", key);
    dictdump(d);
  }
  else {
    d->entry[i] = d->entry[--d.size];
  }
  if ( ((float)d->size)/d.maxsise < 0.25 ) {
    d->maxsize /= 2; 
    d->entry = realloc(d->entry, d->maxsize*sizeof(dictent_t*));
  }

  return d;
}
我使用完整正则表达式的命令如下所示:

 awk '/^[a-zA-Z*_]+[:space:]+[a-zA-Z*_]+[:space:]*\(.*?\)/{ print $0 }' dict3.c 
但我什么也没得到。 所以我试着挤它,只是想看看我能不能带点什么来。 我试过这个:

awk '/^[a-zA-Z*_]+[:space:]+[a-zA-Z*_]+/{ print $0 }' dict3.c 
我明白了:

dictent_t* dictentcreate(const char * key, const char * val) 
dict_t* dictcreate() 
dict_t* dictadd(dict_t* d, const char * key, const char * val) 
dict_t dictup(dict_t d, const char * key, const char * newval) 
dict_t* dictrm(dict_t* d, const char * key) {
这是许多奇迹的来源

  • 为什么第一个正则表达式不起作用
  • 为什么第二份报告抓住了一些声明,但不是全部?我向你保证,在任何声明之前都没有空位。我猜由于缩进,它并没有捕获代码的其他部分,比如变量声明
  • 第三个问题,为什么它抓住了所有我需要表达的地方
  • 最后一个问题,如何添加
    在每个正则表达式的末尾

注意:自从我写下这个答案以来,这个问题已经发生了实质性的变化。

[:space://code>替换为
[:space:]

$ awk '/^[a-zA-Z*_]+[[:space:]]+[a-zA-Z*_]+[[:space:]]*[(].*?[)]/{ print $0 }' dict3.c
dictent_t* dictentcreate(const char * key, const char * val)  
dict_t* dictcreate() 
void dictdestroy(*dict_t d) 
void dictdump(dict_t *d) 
int dictlook(dict_t *d, const char * key) 
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval) 
dict_t* dictrm(dict_t* d, const char * key)
原因是
[:space:][/code>将匹配
s
p
a
c
e
中的任何字符。这不是你想要的

您需要与任何空格匹配的
[[:space:]

Sun/Solaris 本机Sun/solarisawk臭名昭著地充满了bug。如果您在该平台上,请尝试
nawk
/usr/xpg4/bin/awk
/usr/xpg6/bin/awk

使用sed 一种非常类似的方法可用于
sed
。这将使用基于您的正则表达式:

$ sed -n '/^[a-zA-Z_*]\+[ \t]\+[a-zA-Z*]\+ *[(]/p' dict3.c
dictent_t* dictentcreate(const char * key, const char * val)  
dict_t* dictcreate() 
void dictdestroy(*dict_t d) 
void dictdump(dict_t *d) 
int dictlook(dict_t *d, const char * key) 
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval) 
dict_t* dictrm(dict_t* d, const char * key)
-n
选项告诉sed不要打印,除非我们明确要求它打印。构造
/…/p
告诉sed如果斜杠中的正则表达式匹配,则打印该行

埃德·莫顿(Ed Morton)对正则表达式提出的所有改进也适用于此

使用perl perl也可以采用上述方法:

perl -ne  'print if /^[a-zA-Z_*]+[ \t]+[a-zA-Z*]+ *[(]/' dict3.c

您试图编写的regexp是:

$ awk '/^[[:alpha:]_][[:alnum:]_]*\**[[:space:]]+[[:alpha:]_][[:alnum:]_]*[[:space:]]*\([^)]*\)/' file
dictent_t* dictentcreate(const char * key, const char * val)
dict_t* dictcreate()
void dictdestroy(*dict_t d)
void dictdump(dict_t *d)
int dictlook(dict_t *d, const char * key)
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval)
dict_t* dictrm(dict_t* d, const char * key)
$ awk '/^[a-zA-Z_][a-zA-Z0-9_]*\**[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*\([^)]*\)/' file
dictent_t* dictentcreate(const char * key, const char * val)
dict_t* dictcreate()
void dictdestroy(*dict_t d)
void dictdump(dict_t *d)
int dictlook(dict_t *d, const char * key)
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval)
dict_t* dictrm(dict_t* d, const char * key)
在没有字符类的情况下编写并假设您的语言环境是:

$ awk '/^[[:alpha:]_][[:alnum:]_]*\**[[:space:]]+[[:alpha:]_][[:alnum:]_]*[[:space:]]*\([^)]*\)/' file
dictent_t* dictentcreate(const char * key, const char * val)
dict_t* dictcreate()
void dictdestroy(*dict_t d)
void dictdump(dict_t *d)
int dictlook(dict_t *d, const char * key)
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval)
dict_t* dictrm(dict_t* d, const char * key)
$ awk '/^[a-zA-Z_][a-zA-Z0-9_]*\**[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*\([^)]*\)/' file
dictent_t* dictentcreate(const char * key, const char * val)
dict_t* dictcreate()
void dictdestroy(*dict_t d)
void dictdump(dict_t *d)
int dictlook(dict_t *d, const char * key)
int dictget(char* s, dict_t *d, const char *key)
dict_t* dictadd(dict_t* d, const char * key, const char * val)
dict_t dictup(dict_t d, const char * key, const char *newval)
dict_t* dictrm(dict_t* d, const char * key)
但是:

  • 获取/使用具有角色类的awk,因为如果它没有角色类,那么谁知道它还缺少什么
  • 写一个脚本来找到你想要的字符串总是很简单的,但是要想不找到你不想要的字符串却要困难得多。例如,上面的内容将与注释中的文本相匹配,如果给出一个类似
    intfoo(intx/*总是>0(我希望)*/)
    的声明,则会失败。在提供示例输入/输出时,您应该始终包含一些您认为脚本很难不选择的文本,因为这些文本“看起来”很像您确实想要选择的文本,但在错误的上下文中符合您的需要
  • 请注意,C符号不能以数字开头,因此与之匹配的regexp不是
    [:alnum:][uhz]+
    ,而是
    [:alpha:][:alpha:][:alnum:][uhz]*
    。此外,函数可以而且经常返回指向指针的指针,
    *
    可以位于函数名旁边,而不是函数返回类型,因此您确实应该使用这样的regexp(未测试,因为您没有提供匹配格式的输入)如果函数声明可以是任何正常格式:

    awk '/^[[:alpha:]_][[:alnum:]_]*((\*[[:space:]]*)*|(\*[[:space:]]*)*|[[:space:]]+)[[:alpha:]_][[:alnum:]_]*[[:space:]]*\([^)]*\)/' file
    
    当然,这与跨行的声明不匹配——这是另一整罐蠕虫

    一般来说,没有C解析器是无法解析C的,但是如果你想要便宜愉快的东西,那么至少先在代码上运行一个C美化器,尝试将所有可能的布局转换成一种一致的格式(谷歌“C美化器”,你还需要去掉注释(参见示例)

    鉴于您的新需求和新的样本输入/输出,这就是您所要求的:

    $ awk 'match($0,/^[[:alpha:]_][[:alnum:]_]*\**[[:space:]]+[[:alpha:]_][[:alnum:]_]*[[:space:]]*\([^)]*\)/) { print substr($0,RSTART,RLENGTH) ";" }' file
    dict_t dictup(dict_t d, const char * key, const char * newval);
    dict_t* dictrm(dict_t* d, const char * key);
    

    但同样——考虑到C代码的可能布局,这一点也不可靠。你需要一个C解析器、一个C美化器和/或一个专门的工具来可靠地完成这项工作(例如googl
    cscope
    )。

    试着删除
    [:space::]+/code>并添加“+”(space+)@EdMorton,我想是这样,但快速测试(因为我分心了)表示这有帮助,但这可能只是因为我没有注意,其他事情都错了。如果你确定你的文件只有空格,没有选项卡,那么使用真正的空格就可以了。如果你不确定,那么使用
    [[:blank:]
    [:space:]
    。后两个也是unicode安全的。@mklement0是的,您的回答完全正确:ASCII
    \x20
    是一个“空格”,而
    [:blank://code>表示空格或制表符。但是,
    [:space:]
    是指空格、制表符、换行符、换行符、垂直制表符或格式提要中的任何一种。如果我要设计一个有教育意义的命名系统,那就不是这样了。@John1024:好的一点:
    [:space:
    命名不好;应该是
    [:whitespace:
    ,也许。在散文中,是“whitespace”(全部空白)的三位一体“blanks”(空格和/或制表符)和“spaces”(仅限
    \x20
    )对我来说是有意义的。@NicolasScottoDiPerto获得了一个几乎POSIX的awk,其中包括对字符类的支持,如
    [[:space:]
    在Solaris上使用/usr/xpg4/bin/awk,而不是nawk,也绝对不是旧的、坏的awk(/usr/bin/awk)。尽管它的名字叫“新awk”,nawk实际上是一个功能有限的非常古老的awk。这里的教训是——永远不要使用“新”这个词在命名软件时!@NicolasScottoDiPerto您只是选择了错误的awk和sed版本。如果您认为学习perl进行这样的琐碎文本操作是合理的,那么您就偏离了正轨,将浪费大量时间-只需使用标准UNIX工具的当前版本。您一直处于劣势因为Solaris附带了非常旧的sed和awk版本作为默认版本