【问题标题】:How to initialize a pointer to the length of an output buffer?如何初始化指向输出缓冲区长度的指针?
【发布时间】:2015-11-29 10:41:27
【问题描述】:

我正在将此代码用于使用 pcre2 库的正则表达式替换:

PCRE2_SIZE outlengthptr=256;                       //this line
PCRE2_UCHAR* output_buffer;                        //this line
output_buffer=(PCRE2_UCHAR*)malloc(outlengthptr);  //this line
uint32_t rplopts=PCRE2_SUBSTITUTE_GLOBAL;
int ret=pcre2_substitute(
  re1234,                    /*Points to the compiled pattern*/
  subject,               /*Points to the subject string*/
  subject_length,        /*Length of the subject string*/
  0,                     /*Offset in the subject at which to start matching*/
  rplopts,               /*Option bits*/
  0,                     /*Points to a match data block, or is NULL*/
  0,                     /*Points to a match context, or is NULL*/
  replace,               /*Points to the replacement string*/
  replace_length,        /*Length of the replacement string*/
  output_buffer,         /*Points to the output buffer*/
  &outlengthptr          /*Points to the length of the output buffer*/
);

但我似乎不明白如何正确定义 output_buffer 和指向它的长度 (outlengthptr) 的指针。

当我为outlengthptr 提供一个固定值时,该代码有效,但它保持不变,即它不会更改为output_buffer 的新长度。但是根据pcre2_substitue() specification应该改成output_buffer的新长度:

length、startoffset 和 rlength 值是代码单位,而不是字符,outlengthptr 指向的变量的内容也是如此,它会更新为新字符串的实际长度。

问题是:

  1. 当我将outlengthptr 设为固定值时,最终的字符串会以固定长度截断。
  2. 如果我不初始化变量outlengthptr,我会遇到分段错误。

这是函数的原型:

 int pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE startoffset, uint32_t options, pcre2_match_data *match_data, pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength, PCRE2_UCHAR *outputbuffer, PCRE2_SIZE *outlengthptr); 

This is the man page of the function.

【问题讨论】:

  • 好的,如果需要,请尝试分配 64k,调用,然后重新分配。
  • 要获得最佳答案,请发帖MCVE
  • "当我将 outlengthptr 设为固定值时,最终的字符串将被截断为固定长度。" - 我会说这就是它应该如何工作的方式。如果您不希望输出被截断,则传递一个足够大以容纳整个输出的缓冲区。
  • @Jahid 不,不是。调用者负责管理输出缓冲区。
  • @Jahid:没有人粗鲁。我只是澄清了什么是真实的。您问:“如何初始化指向输出缓冲区长度的指针?​​”。好吧,你不能。指针没有像数组那样的长度属性(即 referenced 对象的长度)。根据您使用的语言,这里可能会有不同的答案。

标签: c++ c pointers pcre


【解决方案1】:

pcre2api page 表示以下内容(强调我的):

该函数返回已进行的替换次数。如果未找到匹配项,则该值可能为零,并且永远不会大于 1,除非设置了 PCRE2_SUBSTITUTE_GLOBAL。如果发生错误,则返回负错误代码。除了PCRE2_ERROR_NOMATCH(从不返回),来自pcre2_match() 的任何错误或子字符串复制函数都会直接返回。 PCRE2_ERROR_BADREPLACEMENT 为无效的替换字符串(美元符号后面的无法识别的序列)返回,如果输出缓冲区不够大,则返回 PCRE2_ERROR_NOMEMORY

所以从一个可以容纳大部分结果的初始缓冲区开始——不要太大也不要太小。这取决于您的应用程序。
例如,您可以尝试从输入字符串长度的 120% 作为启发式开始,因为对于大多数常见的正则表达式替换用法来说,这似乎是一个合理的选择。

然后,用这个缓冲区调用函数,并传递它的大小。

  • 如果你得到一个肯定的结果(或零),你就完成了。
  • 如果您收到PCRE2_ERROR_NOMEMORY,则将缓冲区大小加倍并重试(根据需要重复此步骤多次)
  • 如果您收到不同的错误代码,请按照真正的错误情况进行相应处理。

【讨论】:

  • 这是一个很好的解决方法,但它涉及对同一函数的多次调用。这将需要一些额外的时间......
  • @Jahid 我添加了一个段落。如果您明智地选择起始大小,则在大多数情况下,您可以进行 1 或 2 次迭代。一如既往:测量。如果你做了太多的迭代,改变你的假设。如果你做得好,这在实践中不会成为问题。
  • 或者,您可以发送一个功能请求来计算所需的缓冲区大小 - 但这种方法的缺点是 minimal 正则表达式匹配数必须执行的总是 2(一次用于大小估计,一次用于实际替换)。我会说性能损失会更大,因为正则表达式匹配比字符串复制花费更多时间。 理想的功能是要求此函数在返回PCRE2_ERROR_NOMEMORY时将outlengthptr更新为所需的大小,但这将是一个重大更改
  • 我想我会提交一个错误报告,该函数应该根据它的规范更新outlengthptr作为缓冲区大小。
  • 在处理文件时,我将暂时使用 FILENAME_MAX。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 2014-07-12
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
相关资源
最近更新 更多