正则表达式匹配缓慢

regex match slow

本文关键字:缓慢 正则表达式      更新时间:2023-12-22

我试图让nodejs应用程序使用超过2mb的ajax上传文件,
客户端我使用FileReader api保存base64,然后通过FormData

我的问题是下面这样的服务器端代码太慢了,我放了console.log,试图找到哪一部分,当上传更大的文件时,似乎卡在了regex match
有什么建议可以改进吗?

https://regex101.com/r/qS2lB2/1

...
console.log(image.data_base64);  
// 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvd ...
var matches = image.data_base64.match(/^data:.+'/(.+);base64,(.*)$/);
console.log('done');  // slow
var fileExtension = matches[1];
var base64 = matches[2];
var buffer = new Buffer(base64, 'base64');
...
yield Promise.resolve( filesystem().writeFile(temporaryFilePath, buffer) );

如果您出于某种原因仍想使用正则表达式,可以通过将非尾随的.+子模式替换为适当的否定字符类来提高性能,这些类涉及的回溯要少得多。

使用

/^data:[^'/]+'/([^;]+);base64,(.*)$/

请参阅regex演示。

说明:

  • ^-字符串的开头
  • data:-文字字符序列data:
  • [^'/]+-除/之外的1+个字符
  • '/-文字斜杠
  • ([^;]+)-第1组:除;以外的1个字符
  • ;base64,-一个文字字符序列;base,
  • (.*)-第2组:0+除换行符以外的任何字符
  • $—字符串结束

额外的长度意味着正则表达式必须遍历更多的字符串。

在以data:image/jpeg;base64,/9:开头的字符串上测试regex(使用regex101.com,PHP模式)

添加的字符|步数

0   | 63
1   | 68
2   | 73
10  | 113
100 | 563

每个附加字符为5个步骤。

如何修复正则表达式

(基于characters added=100,563步)

  • 你最大的问题是.+

    • 将第一个替换为.+?减少到248步
    • 将第二个替换为.+?使其从248步增加到34步

性能问题的原因

灾难性的回溯。.+会吃掉整个字符串,如果它还需要找到更多的字符,它必须返回,逐个释放字符。.+?是惰性的,这意味着它将尝试在regex中尽快继续,尽可能少地使用字符。

发送multipart/form-data请求中编码的文件base64是不必要的。FileReader有一个.readAsArrayBuffer()方法,它将为您提供可以直接传递给formData.append()的原始数据(作为ArrayBuffer)。