以前一直没用过标准库的regex,今天写一个hlsl的解析工具的时候用了一下,发现用字符串字面值写regular expression的时候非常不方便,特别是每个“\”字符都要被识别为转义,只能写成“\\”。比如,一系列空白字符加一个数字要写成这样:

std::regex reg("\\s*\\d");

这样一来,稍微一复杂的regular expression就完全没法看了。理所当然地,可以用raw string literal来解决这个问题。C++11中raw string literal的写法是这样的:

R"delimiter(string)delimiter"

其中delimiter是用来标识字符串的边界的。比方说——

std::cout << R"__("minecraft")__"

输出的结果就是"minecraft",注意输出的结果是有引号的。

用raw string literal的时候我就觉得,能不能把它搞得更直观一点,比如上面那个regular expression能不能写成

#define RAW_STR(str) something...
std::regex reg(RAW_STR(\s*\d));

于是我试着写了一个

#define RAW_STR(str, delimiter) R##"##delimiter##(##str##)##delimiter##"

结果发现##delimiter##(##str##)##delimiter##直接被两边的引号界定为了字符串字面值,str和delimiter作为宏参数根本没被展开出来。于是加了一层宏——

#define __ADD_QUOT(s) #s

专门用来添加引号。这时候又想起在有##或#的时候宏参数不会被展开,所以加了个中间层来展开参数:

#define __ADD_QUOT(s) __ADD_QUOT_AUX(s)
#define __ADD_QUOT_AUX(s) #s

就这样来来回回加了几个中间层,最后就变成了这样:

#define RAW_STR(str) \
    __RAW_STR_AUX_ADD_R(__RAW_STR_AUX_MAKE_STR(__RAW_STR_AUX_CAT(str)))
#define __RAW_STR_AUX_ADD_R(str) __RAW_STR_AUX_ADD_R1(str)
#define __RAW_STR_AUX_ADD_R1(str) R##str
#define __RAW_STR_AUX_MAKE_STR(cont) __RAW_STR_AUX_MAKE_STR1(cont)
#define __RAW_STR_AUX_MAKE_STR1(cont) #cont
#define __RAW_STR_AUX_CAT(str) __RAW_STR_AUX_CAT1(str)
#define __RAW_STR_AUX_CAT1(str) _____##(##str##)##_____

这里我用四个下划线作为delimiter,一般来说够用了。然后试了一下,还算能用。但是有个毛病没有解决:字面值的两端如果有“,”字符,会被预处理器当做宏参数的分隔符,而非宏参本身的一部分,导致不正确的结果。在写regular expression的时候,把这样的特殊字符用圆括号包起来就行了(反正对语义没有影响),比如

std::regex reg(RAW_STR(minecraft(,)));

当然,这个问题也许有更好的解决方法,以后再慢慢考虑。严格来说,这一堆宏在理论和工程上都没有什么用,就当自己寒假玩一玩了。

利用宏方便地书写raw string literals的更多相关文章

  1. C++11中的raw string literals

    作为一名C++书看得少得可怜的新手,我一直没有勇气去系统地学习一下C++ 11添加的新特性.不过,平日里逛论坛,阅读大犇们的博客,倒是了解了一些.比如,这个帖子: 如何绕过g++ 4.8.1那个不能在 ...

  2. 指针直接赋值为整型AND利用宏定义求结构体成员偏移量

    首先我们要更正一个很熟悉的概念,那就是指针不仅仅是“地址”,指针还有一个很重要的特性,那就是“类型”. 指针初始化时,“=”的右操作数; 除外,该语句表示指针为空): 所以 ; 这样的代码是不允许的. ...

  3. python raw String 获取字符串变量中的反斜杠

    常用的获取raw string的方式为: >>>r'\n' \n 不能用在字符串变量中,获取字符串变量中的反斜杠如下: tab = '\n' >>>tab.enco ...

  4. react 使用 ref 报错 ,[eslint] Using string literals in ref attributes is deprecated. (react/no-string-refs)

    react 项目中给指定元素加事件,使用到 react 的 ref 属性,Eslink 报错 [eslint] Using string literals in ref attributes is d ...

  5. Visual Studio 2010如何利用宏

    最近在做后台代码的拆分,由于机器升级,原来装的添加注释的插件不能用了. 看来只有自己想办法了,看了下利用宏添加注释与把项目展开.折叠的方式: 参考了以下几个内容: 1.Visual Studio 20 ...

  6. (转)react 使用 ref 报错 ,[eslint] Using string literals in ref attributes is deprecated. (react/no-string-refs)

    原文地址:https://www.cnblogs.com/gangerdai/p/7396226.html react 项目中给指定元素加事件,使用到 react 的 ref 属性,Eslink 报错 ...

  7. python中的raw string的使用

    背景 我们经常需要使用raw string,在应用过程中,比如要使字符串中带一些转义字符或者其他的一些符号,我们就需要保持我们的字符成为raw string. 实例 输入 s = 'fadfafa\n ...

  8. C++ raw string literal

    raw string literal 以   R"(  开头, )" 结束,是可以跨越多行的字符串字面值,转义字符如 \t\n 在raw string literal中是普通的文本 ...

  9. word中利用宏替换标点标点全角与半角

    Alt+F11,然后插入-模块: 复制下面代码到编辑窗口: Sub 半角标点符号转换为全角标点符号() '中英互译文档中将中文段落中的英文标点符号替换为中文标点符号 Dim i As Paragrap ...

随机推荐

  1. Nginx在Linux安装详解及问题处理

    Linux编译安装 1.nginx 依赖于prce库,要先安装pcre. #yum install prce pcre-devel 2.下载解压nginx #cd /usr/local/src/ #w ...

  2. 订阅发布模式eventEmiter

    // 订阅发布模式 class EventEmitter { constructor() { this._events = {}; } on(name, callback) { if (this._e ...

  3. PCB Layout初学者必会知识总结(转)

    PCB是印刷电路板(即Printed Circuit Board)的简称.印刷电路板是组装电子零件用的基板,是在通用基材上按预定设计形成点间连接及印制元件的印制板.该产品的主要功能是使各种电子零组件形 ...

  4. 微信小程序跳转问题:wx.redirectTo、wx.navigateTo、wx.reLaunch、wx.switchTap、wx.navigateBack区别

    wx.redirectTo:关闭当前页,跳转到指定页: wx.navigateTo:保留当前页,跳转到指定页: wx.reLaunch:关闭所有页面,打开到应用内的某个页面. wx.switchTap ...

  5. 根据需求定制 admin

    定义 list 页面 自定义 list_filter 首先,完成过滤器的功能,需要自定义过滤器.在 PostAdmin 定义的上方定义如下代码: class CategoryOwnerFilter(a ...

  6. cefsharp wpf

    github 安装 PM> Install-Package CefSharp.Wpf 解决方案->属性->配置属性->活动解决方案平台-新建-x64 在需要使用的窗体上引用xm ...

  7. Centos7.4.1708搭建syslog服务

    系统:centos7.4.1708环境:无互联网环境syslog使用端口为 UDP 514 将/etc/yum.repos.d目录下除CentOS-Media.repo文件所有文件重命名cd /etc ...

  8. Js 监听器

    在Ajax取数据时,采用$("#id").click(function(){})的方式不能正确设置监听,需要用$("#parent").on("cli ...

  9. ES6拓展符修改对象

    // ES6 拓展符合并两个对象let ab = { ...a, ...b }; // 等同于 let ab = Object.assign({}, a, b); // 修改对象部分属性.用户自定义的 ...

  10. python基础知识(循环语句)

    for循环.while循环.循环嵌套 for 迭代变量 In 对象: 循环体 range(start,end,step) 第一个和第三个可以省略生成一系列的连续整数 start 包括起始值 end  ...