正则表达式匹配慢
regex match slow
我尝试让 ajax 使用 nodejs 应用程序上传超过 2mb 的文件,
客户端我使用 FileReader
api 保存 base64 然后通过 FormData
。
我的问题是像下面这样的服务器端代码太慢了,我把 console.log
试着找出哪一部分,当上传更大的文件时,似乎卡在了正则表达式 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) );
无需在 multipart/form-data
请求中发送 base64 编码的文件。 FileReader
有一个 .readAsArrayBuffer()
方法,可以为您提供可以直接传递给 formData.append()
.
的原始数据(作为 ArrayBuffer)
以防万一您出于某种原因仍想使用正则表达式,可以通过将非尾随 .+
子模式替换为涉及更少回溯的适当否定字符 类 来提高性能。
使用
/^data:[^\/]+\/([^;]+);base64,(.*)$/
参见 regex demo。
解释:
^
- 字符串开头
data:
- 文字字符序列 data:
[^\/]+
- /
以外的 1+ 个字符
\/
- 斜杠
([^;]+)
- 第 1 组:;
以外的 1+ 个字符
;base64,
- 文字字符序列 ;base,
(.*)
- 第 2 组:0+ 除换行符外的任何字符
$
- 字符串结尾。
额外的长度意味着正则表达式必须经过的字符串更多。
在以 data:image/jpeg;base64,/9
:
开头的字符串上测试您的正则表达式(使用 regex101.com、PHP 模式)
已添加字符 |步骤
0 | 63
1 | 68
2 | 73
10 | 113
100 | 563
每增加一个字符为 5 个步骤。
如何修复正则表达式
(基于 characters added=100
走 563 步)
你最大的问题是.+
s
- 用 .+ 替换第一个?减少到 248 步
- 将第二个替换为
.+?
将其从 248 步变为 34 步
性能问题的原因
灾难性的回溯。 .+
会吃掉整个字符串,如果还需要找更多的字符,就得返回,一个一个释放字符。 .+?
是惰性的,这意味着它将尝试尽快在正则表达式中继续前进,消耗尽可能少的字符。
我尝试让 ajax 使用 nodejs 应用程序上传超过 2mb 的文件,
客户端我使用 FileReader
api 保存 base64 然后通过 FormData
。
我的问题是像下面这样的服务器端代码太慢了,我把 console.log
试着找出哪一部分,当上传更大的文件时,似乎卡在了正则表达式 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) );
无需在 multipart/form-data
请求中发送 base64 编码的文件。 FileReader
有一个 .readAsArrayBuffer()
方法,可以为您提供可以直接传递给 formData.append()
.
以防万一您出于某种原因仍想使用正则表达式,可以通过将非尾随 .+
子模式替换为涉及更少回溯的适当否定字符 类 来提高性能。
使用
/^data:[^\/]+\/([^;]+);base64,(.*)$/
参见 regex demo。
解释:
^
- 字符串开头data:
- 文字字符序列data:
[^\/]+
-/
以外的 1+ 个字符
\/
- 斜杠([^;]+)
- 第 1 组:;
以外的 1+ 个字符
;base64,
- 文字字符序列;base,
(.*)
- 第 2 组:0+ 除换行符外的任何字符$
- 字符串结尾。
额外的长度意味着正则表达式必须经过的字符串更多。
在以 data:image/jpeg;base64,/9
:
已添加字符 |步骤
0 | 63
1 | 68
2 | 73
10 | 113
100 | 563
每增加一个字符为 5 个步骤。
如何修复正则表达式
(基于 characters added=100
走 563 步)
你最大的问题是
.+
s- 用 .+ 替换第一个?减少到 248 步
- 将第二个替换为
.+?
将其从 248 步变为 34 步
性能问题的原因
灾难性的回溯。 .+
会吃掉整个字符串,如果还需要找更多的字符,就得返回,一个一个释放字符。 .+?
是惰性的,这意味着它将尝试尽快在正则表达式中继续前进,消耗尽可能少的字符。