简体   繁体   English

如何在Cim中将C风格的printf转换为C ++风格的cout

[英]How to convert C style printf to C++ style cout in vim

I got hand over some legacy code and first I want to see if it's possible to change something like 我交出了一些遗留代码,首先我想知道是否可以改变类似的东西

printf("test %d\n", var);

into

std::cout << "test " << var << std::endl;

There are a lot of them and doing them manually is very time consuming. 它们中有很多并且手动完成它们非常耗时。 Is there a way to use vim to make this happen? 有没有办法使用vim来实现这一目标?

The furthest I get is 我得到的最远的是

:%s/printf(\(.*\), \(.*\));/std::cout << \1 << \2 << std::endl;/g

but this only gets me 但这只能得到我

std::cout << "test %d\n" << var << std::endl;

I can apply clang format to the code so in printf I can guarantee there is always a space after a comma. 我可以将clang格式应用于代码,因此在printf中我可以保证逗号后总是有空格。 In this example the space is between comma and var. 在此示例中,空格介于逗号和var之间。

Ideally this vim command would be able to detect the percentage sign to know how many variables is in there and also detect \\n to know when to replace it with std::endl. 理想情况下,这个vim命令能够检测百分比符号以了解其中有多少变量,并且还检测\\ n以知道何时用std :: endl替换它。 Please advice. 请指教。

You could try writing a macro. 你可以试着写一个宏。

First, A macro to convert the "%[insert here]" to the cout format. 首先,一个宏将“%[insert here]”转换为cout格式。

:reg
--- Registers
"f   0f%2xmcf"f,dwdw`ci" << ^[pa << "^[

So what this does on macro key F, is 那么这对宏键F的作用是什么

  1. 0f% Go to the start of the line, find the first percentage sign (assumes % is not used in any other way, sadly) 0f%转到该行的开头,找到第一个百分号(假设%没有以任何其他方式使用,遗憾的是)
  2. 2xmc Delete the %d part, then store the current position in the line on marker c. 2xmc删除%d部分,然后将当前位置存储在标记c的行中。
  3. f"f, Find the end of the string, then find the first comma. f"f,找到字符串的结尾,然后找到第一个逗号。
  4. dwdw Delete the comma, then delete the variable name. dwdw删除逗号,然后删除变量名。 This will allow the variable to be stored so it can be pasted later. 这将允许存储变量,以便稍后粘贴。
  5. [backtick]c Go to the stored position in the line at mark c. [backtick]c转到标记c处的行中的存储位置。
  6. i" << ^[ Insert " << into the string and escape back to command mode. i" << ^[插入" <<进入字符串并退回到命令模式。
  7. pa << "^[ Paste the stored variable name, then insert the string << " . pa << "^[粘贴存储的变量名,然后插入字符串<< "

So, the end result is this 所以,最终结果就是这样

printf("test %d\n", var); // Before
printf("test " << var << "\n"); // After

On another macro key R, simply replay macro F multiple times (say 100). 在另一个宏键R上,简单地多次重放宏F(比如说100)。 It won't finish the macro if you have less than 100 variables because f% will fail. 如果您的变量少于100个,则无法完成宏,因为f%将失败。

:reg
--- Registers
"r   100@f

So, an example would be 所以,一个例子就是

printf("test %d %d %d %d %d\n", var, var1, var2, var3, var4); // Before
printf("test " << var << " " << var1 << " " << var2 << " " << var3 << " " << var4 << "\n"); // After

Now write a macro C to convert the start and end to C++! 现在编写一个宏C来将开始和结束转换为C ++!

:reg
--- Registers
"c   0trcwcout << ^[f(x$F)x
  1. 0tr Go to start of line, and find UNTIL first r. 0tr转到行首,找到UNTIL first r。 This is in case of different indentation levels. 这是在不同缩进级别的情况下。 We will be positioned at the p in printf . 我们将定位于printf中的p
  2. cwcout << ^[ Change printf to cout << and escape to command mode. cwcout << ^[ printf更改为cout <<并转到命令模式。
  3. f(x Find the ( in printf( and delete it. f(x找到(printf(并删除它)。
  4. $F)x Go to the end of the line, find the last ) and delete it. $F)x转至行的末尾,找到最后) ,并删除它。

This gives: 这给出了:

printf("test " << var << " " << var1 << " " << var2 << " " << var3 << " " << var4 << "\n"); // Before
cout << "test " << var << " " << var1 << " " << var2 << " " << var3 << " " << var4 << "\n"; // After

To tie it all together, make another macro T, which finds printf , runs macro C, then runs macro F. It is done in this order so that if an early part fails, the rest of the command won't run. 为了将它们组合在一起,创建另一个宏T,它找到printf ,运行宏C,然后运行宏F.它按此顺序完成,这样如果早期部分失败,则命令的其余部分将不会运行。

:reg
--- Registers
"t   /printf^M@c@r

Running this macro T 3 times does the following: 运行此宏T 3次执行以下操作:

// Before
printf("test %d\n", var);
printf("test %d %d %d %d %d\n", var, var1, var2, var3, var4);
printf("test %d %d\n", var, var2);

// After
cout << "test " << var << "\n";
cout << "test " << var << " " << var1 << " " << var2 << " " << var3 << " " << var4 << "\n";
cout << "test " << var << " " << var2 << "\n";

This solution isn't perfect, it assumes there that percentages aren't used in any other format, and it has to be manually repeated for each printf (spamming @@ ). 这个解决方案并不完美,它假定百分比没有以任何其他格式使用,并且必须为每个printf手动重复(垃圾邮件@@ )。 I hope it is at least useful, and shows the power of vim. 我希望它至少是有用的,并展示了vim的力量。

This is actually harder than it seems, especially if you have more complicated formats with with field-width specifiers or other such things, or worse the "%[" format. 这实际上比看起来更难,特别是如果你有更复杂的格式与字段宽度说明符或其他类似的东西,或更糟糕的"%["格式。 It is also complicated if the arguments to the format string are more complicated than simple variables or literals, for example if you have function calls. 如果格式字符串的参数比简单变量或文字更复杂,例如,如果您有函数调用,那么它也很复杂。

However for simple formatting strings and arguments, such as the printf call shown in the question, it's not that hard to do in a script language. 但是对于简单的格式化字符串和参数,例如问题中显示的printf调用,在脚本语言中并不难。 You get the formatting string and put it in a string variable, then you get all the arguments and put them as a string in another variable. 您获取格式化字符串并将其放在字符串变量中,然后获取所有参数并将它们作为字符串放在另一个变量中。 Split the argument string on comma, and you have a list of the arguments. 在逗号上拆分参数字符串,并且您有一个参数列表。

Then iterate over the formatting string, and when you hit a '%' character, which is not followed by another '%' character, then print the formatting string up to that point and get the first argument from the list of arguments. 然后迭代格式化字符串,当你点击一个'%'字符,后面没有另一个'%'字符,然后打印格式化字符串直到那一点,并从参数列表中获取第一个参数。 Then continue to scan the formatting string and get each corresponding argument from its list when you hit a formatting sequence. 然后继续扫描格式化字符串,并在单击格式化序列时从其列表中获取每个对应的参数。

我匹配了%d\\n"在捕获之外并在替换中添加了空格和结束”。

:%s/printf(\(.*\) \S\+, \(.*\));/std::cout << \1 " << \2 << std::endl;/g

Answer needs to be more generic! 答案需要更通用! So, we can use a vim function to detect both % characters like %d%f%s as well as escape sequence characters like \\n\\r . 因此,我们可以使用vim函数来检测%d%f%s%字符以及\\n\\r类的转义序列字符。

Just a sample psuedocode. 只是一个样本的伪代码。

        :function ConvertToCPP()
        :let a = getline('.')
        : while a doesn't contain % or \ characters
        :    take any number of  \n and put as endl at end of line, if any
        :   remove off the % characters.
        : put << in between each of them
        :   call setline ('.', a)
        :return 1
        :end function

Noe, you can call this function with range, such that it will easily replace them all. 不,你可以用范围调用这个函数,这样它就可以轻松地替换它们。

    :10,20ConvertToCPP()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM