我对此感到疯狂,所以我有很多这样的:
VfxEmitterDefinitionData {
BindWeight: embed = ValueFloat {
ConstantValue: f32 = 0
}
IsSingleParticle: flag = true
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "distort"
}
}
}
EmitterName: string = "distort"
}
VfxEmitterDefinitionData {
BindWeight: embed = ValueFloat {
ConstantValue: f32 = 0
}
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "DarkCore"
}
}
}
EmitterName: string = "DarkCore"
IsSingleParticle: flag = true
}
我想使用查找和替换将它们变成这些:
"distort" = VfxSystemDefinitionData {
ComplexEmitterDefinitionData: list[pointer] = {
VfxEmitterDefinitionData {
BindWeight: embed = ValueFloat {
ConstantValue: f32 = 0
}
IsSingleParticle: flag = true
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "distort"
}
}
}
EmitterName: string = "distort"
}
}
ParticleName: string = "distort"
ParticlePath: string = "distort"
}
"DarkCore" = VfxSystemDefinitionData {
ComplexEmitterDefinitionData: list[pointer] = {
VfxEmitterDefinitionData {
BindWeight: embed = ValueFloat {
ConstantValue: f32 = 0
}
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "DarkCore"
}
}
}
EmitterName: string = "DarkCore"
IsSingleParticle: flag = true
}
}
ParticleName: string = "DarkCore"
ParticlePath: string = "DarkCore"
}
基本上只是想在开始时添加这个:
"(Name from EmitterName)" = VfxSystemDefinitionData {
ComplexEmitterDefinitionData: list[pointer] = {
这位于每个 VfxEmitterDefinitionData 的末尾:
}
ParticleName: string = "(Name from EmitterName)"
ParticlePath: string = "(Name from EmitterName)"
}
即使忽略名称部分并只专注于在括号之间进行选择,我也找不到一种方法来匹配它们中的每一个,我已经尝试过
VfxEmitterDefinitionData \{[\s\S\r]*\}
,但这会选择文件中的所有它们,就好像它是一个一样,并且VfxEmitterDefinitionData \{[\s\S\r]*?\}
它确实选择了它们中的每一个,但仅在第一个左括号和第一个右括号之间进行选择。
那么使用 VS Code 是否可以做到这一点,还是太复杂了?还有其他工具可以帮助完成此类工作吗?
如果您的内容中包含大括号,这可能会变得相当棘手 字符串:
"Example of \"moustache\" emoji face => :-{"
或在评论中:
// Use a closing curly bracket "}" to close your block.
这意味着正则表达式必须考虑 字符串和注释中的大括号以获得平衡 打开/关闭块正确。这就是为什么它可以快速到达 正则表达式引擎的局限性!
PHP 的 PCRE 引擎接受递归,所以你可以使用另一个 编辑器或工具来更改您的文件。
但是由于您需要捕获部分代码 发射器的名称,我想你必须编写一个脚本来 转换您的文件。这就是我在 PHP 中使用 PCRE 所做的
x
标志,可让您在多个上添加注释并编写正则表达式
线。同时,我们可以声明一些其他模式
在主模式中重用(有点像函数)。这使得
更容易编写和理解。
匹配块的正则表达式模式,使用
~
作为
模式分隔符,这样我就可以使用 /
而无需转义它:
~
(?(DEFINE) # Define some sub-patterns for later use and readability.
(?<comment>
/{2}[^\r\n]* # Line comment: // Blabla
| # or
/\*[\s\S]*?\*\/ # Block comment: /* Blabla */
)
(?<string>
" # Opening double-quote.
(?:
\\[\\"] # Backslash or double-quote: \\ or \"
| # or
[^"] # Any char not being a double-quote.
)*
" # Closing double-quote.
)
(?<balanced_braces>
\{
(?: \s* | \g<comment> | \g<string> | [^{}"]* | \g<balanced_braces> )*?
\}
)
)
# Pattern starts here:
(?<block>
\h*
VfxEmitterDefinitionData
\s*
\g<balanced_braces>
)
~gxu
在这里测试:https://regex101.com/r/nR7ey2/1
一些细节:
分隔符和标志:
~
是模式分隔符(通常是 JS 中的 /
)。x
用于 ex 的语法(注释和空格)。g
用于 g全局匹配,意味着匹配所有出现的情况。
这将在 PHP 脚本中被删除,因为它是一个参数。u
代表 unicode。(?(DEFINE) ... )
是可以声明子模式的部分
就像函数一样。这是为了帮助编写复杂的模式。
(?<your_pattern> ... )
是声明子模式/函数的方式。
当你想使用它时,你使用 \g<your_pattern>
。\k<your_pattern>
不同,后者用于
引用与模式匹配但不是模式的文本
图案本身。
行注释是两个斜杠,后跟任何不是的字符 回车或换行字符。
块注释
/* */
包含任何内容(以一种不贪婪的方式,
使用 [\s\S]
而不是 .
,这样我们就不需要启用
s
标志使点与新行匹配)。
字符串以
"
开头,然后可以包含多个内容,
多次:
\\
\"
\n
、\t
等,但至少
在匹配任何字符之前,我们已经“吃掉”了反斜杠。
这样它通常应该正确匹配完整的字符串。我做到了
不要尝试匹配像 'Hello'
这样的单引号字符串。然后,在搜索完注释和字符串后,我们可以尝试 匹配任何不是大括号或双引号的字符。
递归是通过寻找平衡大括号块来完成的 通过用
\g<balanced_braces>
来引用它,即使在它的
自己的定义。
我使用
preg_replace_callback()
因为我们想要提取
找到的块中的发射器名称。这是在回调中完成的
在更换步骤中起作用。
我真的不确定这个脚本是否能够在大文件上运行 由于递归,它可能很快就会遇到 PCRE 的限制 和复杂的分析。您可能需要更改一些 INI 设置 PCRE 甚至调整脚本以首先找到 有趣的块,然后提取块本身来使用 需要分析的字符串较短。
经过修改的输入的 PHP 代码,以显示可能存在的问题。 语法颜色突出显示在 stackoverflow 上有错误,因为它没有 处理 PHP 的 Heredoc 语法:
<?php
/**
* @author Patrick Janser
* @see https://stackoverflow.com/questions/77692961/how-to-find-and-replace-between-brackets-using-regex-in-vs-code
*/
//ini_set('pcre.backtrack_limit', 100000000); // default is 1000000.
//ini_set('pcre.backtrack_recursion', 10000000); // default is 100000.
define('EXIT_PCRE_ERROR', 1);
// A regex to find a VfxEmitterDefinitionData block.
define('REGEX_BLOCK', <<<'END_OF_REGEX'
~
(?(DEFINE) # Define some sub-patterns for later use and readability.
(?<comment>
/{2}[^\r\n]* # Line comment: // Blabla
| # or
/\*[\s\S]*?\*\/ # Block comment: /* Blabla */
)
(?<string>
" # Opening double-quote.
(?:
\\[\\"] # Backslash or double-quote: \\ or \"
| # or
[^"] # Any char not being a double-quote.
)*
" # Closing double-quote.
)
(?<balanced_braces>
\{
(?: \s* | \g<comment> | \g<string> | [^{}"]* | \g<balanced_braces> )*?
\}
)
)
# Pattern starts here:
(?<block>
\h*
VfxEmitterDefinitionData
\s*
\g<balanced_braces>
)
~xu
END_OF_REGEX
);
// To capture the emitter of the VfxEmitterDefinitionData block.
define('REGEX_EMITTER', <<<'END_OF_REGEX'
/
EmitterName\s*:\s*string\s*=\s*"
(?<id>
(?:
\\[\\"] # Backslash or double-quote: \\ or \"
| # or
[^"] # Any char not being a double-quote.
)*
)
"
/xu
END_OF_REGEX
);
// Use this to read a file instead.
//$input = file_get_contents('your-input-file.code');
$input = <<<'END_OF_INPUT'
VfxEmitterDefinitionData {
BindWeight: embed = ValueFloat {
// A comment with a "{" which could break things.
// Another comment.
ConstantValue: f32 = 0
}
IsSingleParticle: flag = true
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "\"distort\"\n}"
}
}
}
EmitterName: string = "\"distort\"\n}"
}
// We could have spaces before too
VfxEmitterDefinitionData {
/* A block comment {:-) */
BindWeight: embed = ValueFloat {
ConstantValue: f32 = 0
}
ChildParticleSetDefinition: pointer = VfxChildParticleSetDefinitionData {
ChildrenIdentifiers: list[embed] = {
VfxChildIdentifier {
EffectKey: hash = "DarkCore :-{"
}
}
}
EmitterName: string = "DarkCore :-{"
IsSingleParticle: flag = true
}
END_OF_INPUT;
print "Input\n=====\n\n$input\n\n";
$output = preg_replace_callback(
REGEX_BLOCK,
function ($match) {
$block = $match[0];
// 1. Extract the emitter.
if (preg_match(REGEX_EMITTER, $block, $subMatch)) {
$emitterString = '"' . $subMatch['id'] . '"';
} else {
die("Could not find the id inside the block :-(\n");
}
// Wrap the found block in it's container.
return "$emitterString = VfxSystemDefinitionData {\n" .
" ComplexEmitterDefinitionData: list[pointer] = {\n" .
// Indent the block 2 times to the right = 8 spaces.
preg_replace('~^~m', ' ', $block) . "\n" .
" ParticleName: string = $emitterString\n" .
" ParticlePath: string = $emitterString\n" .
"}\n";
},
$input
);
if (is_null($output)) {
fprintf(STDERR, "PCRE error %d: %s\n", preg_last_error(), preg_last_error_msg());
exit(EXIT_PCRE_ERROR);
}
print "Output\n======\n\n$output";
您可以在这里运行演示:https://onlinephp.io/c/48450