【问题标题】:How to escape string for generated C++?如何为生成的 C++ 转义字符串?
【发布时间】:2013-02-03 09:39:52
【问题描述】:

我正在编写基于数据生成 C++ 代码的 python 脚本。

我有 python 变量string,其中包含一个可以组合的字符串 " 或换行符之类的字符。

转义此字符串以生成代码的最佳方法是什么?

【问题讨论】:

  • 使用jinja 之类的模板引擎不是最好的解决方法,它已经可以转义字符;我知道我以前在生成 Java 代码时做过类似的事情——我知道我可能误解了你的问题。

标签: python escaping code-generation


【解决方案1】:

我使用的方式是基于对 C++ 字符串的观察 遵守与 Javascript/JSON 字符串一样的字符和转义规则。

Python 从 2.6 版本开始有一个内置的 JSON 库,可以序列化 Python 数据转换成 JSON。因此,代码是,假设我们不需要封闭 引号,如下:

import json
string_for_printing = json.dumps(original_string).strip('"')

【讨论】:

  • 除非字符串中有 Unicode 字符。或者当它以引用结尾时。也不适用于二进制数据。在保持可读性的同时为 C++ 转义任意数据并不像听起来那么容易——我上次这样做时,我只是把每个字节都变成了 \xNN 形式。
  • @MattiVirkkunen 当然对于任意数据,您需要像xxd -i 这样的十六进制转储。但是如果你可以限制到一个合理的字符子集,有没有一个工具可以做到这一点?
【解决方案2】:

我使用这个代码,到目前为止没有问题:

def string(s, encoding='ascii'):
   if isinstance(s, unicode):
      s = s.encode(encoding)
   result = ''
   for c in s:
      if not (32 <= ord(c) < 127) or c in ('\\', '"'):
         result += '\\%03o' % ord(c)
      else:
         result += c
   return '"' + result + '"'

它使用八进制转义符来避免所有可能有问题的字符。

【讨论】:

    【解决方案3】:

    我们可以使用此处找到的 C 细节 (https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Character-Constants) 和 Python 的内置可打印函数做得更好:

    def c_escape():
      import string
      mp = []
      for c in range(256):
        if c == ord('\\'): mp.append("\\\\")
        elif c == ord('?'): mp.append("\\?")
        elif c == ord('\''): mp.append("\\'")
        elif c == ord('"'): mp.append("\\\"")
        elif c == ord('\a'): mp.append("\\a")
        elif c == ord('\b'): mp.append("\\b")
        elif c == ord('\f'): mp.append("\\f")
        elif c == ord('\n'): mp.append("\\n")
        elif c == ord('\r'): mp.append("\\r")
        elif c == ord('\t'): mp.append("\\t")
        elif c == ord('\v'): mp.append("\\v")
        elif chr(c) in string.printable: mp.append(chr(c))
        else:
          x = "\\%03o" % c
          mp.append(x if c>=64 else (("\\%%0%do" % (1+c>=8)) % c, x))
      return mp
    

    这具有现在是从字符ord(c) 的序数值到精确字符串的映射的优点。将+= 用于字符串是缓慢且不好的做法,因此这允许"".join(...) 在Python 中性能更高。更不用说,索引列表/表比每次都对字符进行计算要快得多。也不要通过检查是否需要更少的字符来浪费八进制字符。但是,要使用它,您必须验证下一个字符不是 07,否则您必须使用 3 位八进制格式。

    表格如下:

    [('\\0', '\\000'), ('\\1', '\\001'), ('\\2', '\\002'), ('\\3', '\\003'), ('\\4', '\\004'), ('\\5', '\\005'), ('\\6', '\\006'), '\\a', '\\b', '\\t', '\\n', '\\v', '\\f', '\\r', ('\\16', '\\016'), ('\\17', '\\017'), ('\\20', '\\020'), ('\\21', '\\021'), ('\\22', '\\022'), ('\\23', '\\023'), ('\\24', '\\024'), ('\\25', '\\025'), ('\\26', '\\026'), ('\\27', '\\027'), ('\\30', '\\030'), ('\\31', '\\031'), ('\\32', '\\032'), ('\\33', '\\033'), ('\\34', '\\034'), ('\\35', '\\035'), ('\\36', '\\036'), ('\\37', '\\037'), ' ', '!', '\\"', '#', '$', '%', '&', "\\'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '\\?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\\177', '\\200', '\\201', '\\202', '\\203', '\\204', '\\205', '\\206', '\\207', '\\210', '\\211', '\\212', '\\213', '\\214', '\\215', '\\216', '\\217', '\\220', '\\221', '\\222', '\\223', '\\224', '\\225', '\\226', '\\227', '\\230', '\\231', '\\232', '\\233', '\\234', '\\235', '\\236', '\\237', '\\240', '\\241', '\\242', '\\243', '\\244', '\\245', '\\246', '\\247', '\\250', '\\251', '\\252', '\\253', '\\254', '\\255', '\\256', '\\257', '\\260', '\\261', '\\262', '\\263', '\\264', '\\265', '\\266', '\\267', '\\270', '\\271', '\\272', '\\273', '\\274', '\\275', '\\276', '\\277', '\\300', '\\301', '\\302', '\\303', '\\304', '\\305', '\\306', '\\307', '\\310', '\\311', '\\312', '\\313', '\\314', '\\315', '\\316', '\\317', '\\320', '\\321', '\\322', '\\323', '\\324', '\\325', '\\326', '\\327', '\\330', '\\331', '\\332', '\\333', '\\334', '\\335', '\\336', '\\337', '\\340', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347', '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357', '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367', '\\370', '\\371', '\\372', '\\373', '\\374', '\\375', '\\376', '\\377']
    

    将一些 4 字节整数编码为小端字节顺序的 C 字符串的示例用法,每 50 个字符插入新行: v

    mp = c_escape()
    vals = [30,50,100]
    bytearr = [z for i, x in enumerate(vals) for z in x.to_bytes(4, 'little', signed=x<0)]
    "".join(mp[x] if not type(mp[x]) is tuple else mp[x][1 if not i == len(bytearr)-1 and bytearr[i+1] in list(range(ord('0'), ord('7')+1)) else 0] + ("\"\n\t\"" if (i % 50) == 49 else "") for i, x in enumerate(bytearr))
    
    #output: '\\36\\0\\0\\0002\\0\\0\\0d\\0\\0\\0'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 2016-10-23
      • 1970-01-01
      • 2021-11-05
      相关资源
      最近更新 更多