屠龙之术--基于C语言的正则表达式应用


朱泙漫学屠龙于支离益,单千金之家,三年技成而无所用其巧。
--《庄子·列御寇》

屠龙之术是一个汉语成语,读音tú lóng zhī shù,意思是指极为高明的技术或本领,但是在现实中用不到。


regcomp函数:

功能描述: 把指定的正则表达式编译成一种特定的数据格式。
函数原型: int regcomp(regex_t *preg, const char *regex, int cflags);
参数说明: 

  regex_t 结构体数据类型,用来存放编译后的正则表达式,它的成员re_nsub 用来存储正则表达式中的子正则表达式的个数,子正则表达式就是用圆括号包起来的部分表达式。
regex: 是指向我们写好的正则表达式的指针。
cflags: 有如下4个值或者是它们或运算(|)后的值:
REG_EXTENDED 以功能更加强大的扩展正则表达式的方式进行匹配。
REG_ICASE 匹配字母时忽略大小写。
REG_NOSUB 不用存储匹配后的结果,只返回是否成功匹配。如果设置该标志位,那么在regexec(在下边介绍)将忽略nmatch和pmatch两个参数。
REG_NEWLINE 识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配。

C语言中使用正则表达式一般分为三步:
编译正则表达式 regcomp()
匹配正则表达式 regexec()
释放正则表达式 regfree()


例程:

#include <stdio.h>
#include <string.h>
#include <regex.h>
 
int main(int argc, char** argv)
{
  int x;
  int ret;
  int lno = 0;        // 行号
  int cflags = 0;     // 参数
  char *p;
  char ebuf[128];     // 错误信息
  char lbuf[256];     // 行缓冲区
  regex_t reg;        // 正则表达结构体
  regmatch_t pm[10];  // 匹配列表
  const size_t nmatch = 10;

  // 编译正则表达式
  p = argv[1];
  ret = regcomp(&reg, p, cflags);
  if (ret != 0)
  {
    regerror(ret, &reg, ebuf, sizeof(ebuf));
    fprintf(stderr, "%s: pattern '%s' \n", ebuf, p);
    return 1;
  }

  // 逐行处理输入的数据
  while(fgets(lbuf, sizeof(lbuf), stdin))
  {
    ++lno;
    // 用正则表达式进行匹配
    ret = regexec(&reg, lbuf, nmatch, pm, 0);
    if (ret == REG_NOMATCH)
    {
      continue;
    }
    else if (ret != REG_NOERROR)
    {
      regerror(ret, &reg, ebuf, sizeof(ebuf));
      fprintf(stderr, "%s: regcom('%s')\n", ebuf, lbuf);
      return 2;
    }

    // 打印匹配行(不需要换行)
    printf("%04d: %s", lno, lbuf);    
  }
  // 重新编译正则表达式前,必须清空之前的编译结果
  regfree(&reg);
  return 0;
}

测试命令:

./regs  "^[\t\ ]*r" < regs.c
0014:   regex_t reg;        // 正则表达结构体
0015:   regmatch_t pm[10];  // 匹配列表
0020:   ret = regcomp(&reg, p, cflags);
0023:     regerror(ret, &reg, ebuf, sizeof(ebuf));
0025:     return 1;
0033:     ret = regexec(&reg, lbuf, nmatch, pm, 0);
0040:       regerror(ret, &reg, ebuf, sizeof(ebuf));
0042:       return 2;
0049:   regfree(&reg);
0050:   return 0;
0071:   return stbuf;

https://www.cnblogs.com/liudw-0215/p/9724347.html

- 阅读全文 -

Linux应用程序--syslog应用


文章摘要:
syslog常被称为系统日志或系统记录,在Linux守护进程中,经常需要打印一些调试信息至日志中,用于调试及问题排查,可以输出至syslog中,通过操作系统自带的日志功能来管理运行日志。

#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>

// 输入格式化信息至日志文件 
void glog(char *fmt, ...)
{
    static int open = 0;
    va_list ap;
    char buff[4096];   
    
    if (open == 0) 
    {
        openlog("[test]", LOG_CONS|LOG_PERROR, LOG_USER);   
        open = 1;
    }
    
    va_start(ap, fmt);
    vsnprintf(buff, sizeof(buff), fmt, ap);
    va_end(ap);
    syslog(LOG_INFO, "%s", buff);
}

// 输入内存查看至日志
void glog_dump(unsigned char *buff, int cnt)
{
    char logbuf[4096];
    int sp = 0;
    unsigned char *p = (unsigned char *)buff;
    while (cnt--)
    {
        sp += snprintf(&logbuf[sp], sizeof(logbuf) - sp, "%02X ", *p++);
    }
    syslog(LOG_INFO, "%s", logbuf);
}

// 测试函数    
int main(int argc, char** argv)
{
    unsigned char idx = 0;
    while(1)
    {
        glog("Hello World %d", idx++);
        sleep(2);   
    }
  return 0;
}

注意事项: syslog 不支持换行


查看日志:

$ sudo grep test /var/log/message    
Dec 24 02:35:22 localhost [test]: Hello World 0
Dec 24 02:35:24 localhost [test]: Hello World 1
Dec 24 02:35:26 localhost [test]: Hello World 2
Dec 24 02:35:28 localhost [test]: Hello World 3
Dec 24 02:35:30 localhost [test]: Hello World 4
Dec 24 02:35:32 localhost [test]: Hello World 5

- 阅读全文 -

C语言编程--cjson库应用


文章摘要: 本文主要对单片机及Linux中对cjson库的应用,进行了详细说明。
通过验证,对于封装json格式,调用cjson库并不好用,还不如sprintf拼接更省事,特别对于浮点型小数,解析格式倒是不错。


Linux应用

安装cjson库:

sudo apt-get install libcjson-dev

编译选项: -lcjson


单片机:
下载cjson源码:https://github.com/arnoldlu/cJSON
只需将cJSON.h/cJSON.c代码加入工程编译即可。


cJSON_CreateObject():创建一个json数据结点;
cJSON_AddStringToObject():添加一个字符串数据;
cJSON_AddNumberToObject():添加一个数值数据;
cJSON_AddItemToObject():添加一个json项目;
cJSON_CreateArray():添加一个json数组;
cJSON_Print():转换json数据为字符串;
cJSON_Delete():销毁json数据,注意通过cJSON_Parse()创建的json数据中分配了堆存储,必须通过cJSON_Delete()注销才能释放空间;


示例代码: encode.c

#include <stdio.h>
#include "cJSON.h"
int main()
{
    cJSON * root =  cJSON_CreateObject();
    cJSON * item =  cJSON_CreateObject();
    cJSON * next =  cJSON_CreateObject();
 
    // 根节点下添加
    cJSON_AddItemToObject(root, "rc",        cJSON_CreateNumber(0));
    cJSON_AddItemToObject(root, "operation", cJSON_CreateString("CALL"));
    cJSON_AddItemToObject(root, "service",   cJSON_CreateString("telephone"));
    cJSON_AddItemToObject(root, "text",      cJSON_CreateString("打电话给张三"));
    
    //root节点下添加semantic子节点
    cJSON_AddItemToObject(root, "semantic", item);
    
    //semantic节点下添加item子节点
    cJSON_AddItemToObject(item, "slots", next);
    //添加name节点
    cJSON_AddItemToObject(next, "name", cJSON_CreateString("张三"));
 
    printf("%s\n", cJSON_Print(root));
 
    return 0;
}

执行结果:

{
        "rc":   0,
        "operation":    "CALL",
        "service":      "telephone",
        "text": "打电话给张三",
        "semantic": {
                "slots":{
                        "name": "张三"
                }
        }
}

decode.c

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

// 以递归的方式打印json的最内层键值对 
void printJson(cJSON * root)
{
    for(int i=0; i<cJSON_GetArraySize(root); i++)   //遍历最外层json键值对
    {
        cJSON * item = cJSON_GetArrayItem(root, i);        
        if(cJSON_Object == item->type)      //如果对应键的值仍为cJSON_Object就递归调用printJson
        {
            printf("----------------------\r\n");
            printJson(item);    // 递归
        }
        else                                //值不为json对象就直接打印出键和值
        {
            printf("%s->", item->string);
            printf("%s\n", cJSON_Print(item));
        }
    }
}
 
int main()
{
    char * jsonStr = "{\"semantic\":{\"slots\":{\"name\":\"张三\"}}, \"rc\":0, \"operation\":\"CALL\", \"service\":\"telephone\", \"text\":\"打电话给张三\"}";
    cJSON * root = NULL;
    cJSON * item = NULL;//cjson对象
 
    root = cJSON_Parse(jsonStr);     
    if (!root) 
    {
        printf("Error before: [%s]\n",cJSON_GetErrorPtr());
    }
    else
    {
        printf("%s\n", "有格式的方式打印Json:");           
        printf("%s\n\n", cJSON_Print(root));
 #if 0       
        printf("%s\n", "无格式方式打印json:");
        printf("%s\n\n", cJSON_PrintUnformatted(root));
 #endif
        printf("%s\n", "一步一步的获取name 键值对:");
        printf("%s\n", "获取semantic下的cjson对象:");
        item = cJSON_GetObjectItem(root, "semantic");//
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "获取slots下的cjson对象");
        item = cJSON_GetObjectItem(item, "slots");
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "获取name下的cjson对象");
        item = cJSON_GetObjectItem(item, "name");
        printf("%s\n", cJSON_Print(item));
 
        printf("%s:", item->string);   //看一下cjson对象的结构体中这两个成员的意思
        printf("%s\n", item->valuestring);                        
 
        printf("\n%s\n", "打印json所有最内层键值对:");
        printJson(root);
    }
    return 0;    
}

- 阅读全文 -

MQTT服务器搭建及测试


操作系统:Debian 8 / raspi

在线安装:

$ sudo apt-get install mosquitto

源码安装:

$ git clone https://github.com/eclipse/mosquitto.git
$ cd mosquitto
$ make && make install 

修改config.mk

WITH_DOC=no

需要安装的依赖库:

$ sudo apt-get install libssl-dev libcjson-dev xsltproc

新建配置文件:
在/etc/mosquitto/conf.d目录下,建立test.conf,内容如下:

# 关闭匿名访问,客户端必须使用用户名
allow_anonymous false

# 指定用户名-密码文件(不需要创建该文件,新建用户时会自动创建)
password_file /etc/mosquitto/pwfile.txt

通过命令新建用户:

$ sudo mosquitto_passwd -c /etc/mosquitto/pwfile.txt user
Password: 
Reenter password:

该命令会重新密码文件(会清除掉原来的数据)内容如下:

user:$6$U6n6MqxF2hiuugbv$Pm3t3Ak+vVEGDxozv005AK+G4WF1KO5MzF3U9L87A2C9fR0efWGu+CM789FokdOK046dp12FXdSCOMTW1ijhAg==

可以直接编辑该文件添加或者删除用户。

修改用户密码:

$ sudo mosquitto_passwd -U /etc/mosquitto/pwfile.txt user

删除用户命令:

$ sudo mosquitto_passwd -D /etc/mosquitto/pwfile.txt user

下载iphone手机客户端:
从App Store下载 MQTTool应用


基于LinuxC的应用程序

编译库:

$ git clone https://github.com/eclipse/paho.mqtt.c.git
$ cd paho.mqtt.c
$ make && make install

安装目录:
库文件/usr/local/lib/
头文件/usr/local/include/


例程源文件在src/samples中,编译后的可执行文件在build/output/samples目录中。

编译命令:

cc -o subscribe subscribe.c -lpaho-mqtt3cs 

// 清除会话: 如果设置为1,将清除历史消息
conn_opts.cleansession = 0;
// 设置保持在线时长
conn_opts.keepAliveInterval = 20;
// 设置用户名密码
conn_opts.username = "user";
conn_opts.password = "123456";

https://www.cnblogs.com/lulipro/p/10914482.html

- 阅读全文 -

C++Builder--杂项


生成独立运行程序
Project-->Options...
取消勾选Packages中的Build with runtime packages
取消勾选Linker中的Use dynamic RTL


文本框滚动至最后一行:

Memo1->SelStart  = Memo1->Text.Length();
Memo1->SelLength = 0;

修改图标:
Project-->Options...-->Application-->Load Icon


修改任务管理器显示的名称:
Application->ExeName 运行程序的名称


蜂鸣器响函数:

Beep();

显示信息框:

ShowMessage("Hello World");
MessageBox(this->Handle,"Hello World","Title", MB_OK);

其他注意事项:
Substring从1开始算起


ChangeFileExt 修改文件扩展名


待处理事件:
验证默认参数值的方法
验证消息机制


不生成备份文件
在菜单上找到的Tools->Editor options->display, 将create backup file取消勾选。

指定obj文件输出位置:
project->Options->directories/conditionals --> intermediate output.

指定生成exe文件位置:
project->Options->directories/conditionals --> final output中指定文件夹。

项目文件另存为,放在项目文件夹中,将其他源文件保存在子文件夹中。最终将各种文件分别放在各自的文件夹中

http://blune.blog.sohu.com/71519837.html

- 阅读全文 -


Copyright©2025 春天花会开, All Rights Reserved. Email: webmaster@oroct.com