Board logo

标题: [问题求助] [已解决]用正则表达式中的平衡组删除或修改特定字段 [打印本页]

作者: 小白龙    时间: 2023-5-9 14:20     标题: [已解决]用正则表达式中的平衡组删除或修改特定字段

本帖最后由 小白龙 于 2023-5-10 18:19 编辑

我要修改的多行字符串是一段C#代码, 里面{}环环相套! 可能必须要用平衡组了!

要点1: 类名和函数名后面的 { 的位置有如下两种情况
情况一 { 在新的行中
string FUN1()
{
}
情况二 { 在同一行的末尾
string FUN1() {
}

要点2: 函数的参数里可能有()嵌套()的情况
函数体里可能有{}嵌套{}的情况

要点3: 既要界定返回值类型的文本, 又要判断修饰词是否存在
感觉那三个需求, 用2个正则平衡式应该可以实现

下面代码的注释中有详细的描述, 请求路过大佬帮忙
情况1中的代码可以删除FUN1了, 但是因为没有使用平衡组, 如果{}互相嵌套就不灵了
  1. #--------------------------------------------------------------------情况1: 函数FUN1返回值类型void
  2. $s1 = @'
  3. using System;
  4. public class CLA
  5. {
  6. void FUN1()
  7. {
  8. Console.WriteLine("FUN1");
  9. }
  10. }
  11. '@
  12. $s1 -replace '(?s)void FUN1\(\).*?\}', ''
  13. #--------------------------------------------------------------------情况2: 返回值类型改为了 string
  14. $s2 = @'
  15. using System;
  16. public class CLA
  17. {
  18. string FUN1()
  19. {
  20. return "FUN1";
  21. }
  22. }
  23. '@
  24. #--------------------------------------------------------------------情况3: 加了修饰词 public
  25. $s3 = @'
  26. using System;
  27. public class CLA
  28. {
  29. public void FUN1()
  30. {
  31. Console.WriteLine("FUN1");
  32. }
  33. }
  34. '@
  35. #--------------------------------------------------------------------情况4: 加了修饰词 public static
  36. $s4 = @'
  37. using System;
  38. public class CLA
  39. {
  40. public static string FUN1()
  41. {
  42. return "FUN1";
  43. }
  44. }
  45. '@
  46. # 需求1 用1个正则表达式能删除指定函数名的函数, 要考虑函数名前的多种修饰词的情况
  47. #例如: 把上面四种情况中的 FUN1 函数删除掉
  48. # 需求2 用正则表达式: 修改指定函数名前的修饰词(不要修改返回值类型)
  49. #例如: 把 FUN1 函数的修饰词改为 public static (如果没有修饰词就加上,如果有就修改)
  50. # 需求3 用正则表达式: 修改指定类名前的修饰词
  51. #例如: 把 CLA 类的修饰词改为 private (如果没有修饰词就加上,如果有就修改)
复制代码

作者: 小白龙    时间: 2023-5-9 14:52

本帖最后由 小白龙 于 2023-5-9 15:08 编辑

chatgpt的正则都太局限了也没用平衡组, 求路过大老出招, 优化改进一下!

-replace '(?s)(void|string)\s+FUN1\(\).*?\}', ''

-replace '(?<=\bstring)\s+(?=FUN1\(\))', 'public static'

-replace '(?<=class\s+)\w+', 'private'
作者: idwma    时间: 2023-5-9 17:19

多问几次试试

作者: 小白龙    时间: 2023-5-9 17:46

回复 3# idwma

多谢大佬, 这个正则只适用, void 前置关键字的情况, 还有其它几种

@"void\s+FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}"
作者: 小白龙    时间: 2023-5-9 17:56

回复 3# idwma

替换成前置都能替换成功, 但是前置的关键词情况太多了, 怎样通用呢
  1. #--------------------------------------------------------------------情况1: 函数FUN1返回值类型void
  2. $s1 = @'
  3. using System;
  4. public class CLA
  5. {
  6. void FUN1()
  7. {
  8. Console.WriteLine("FUN1");
  9. }
  10. }
  11. '@
  12. #--------------------------------------------------------------------情况2: 返回值类型改为了 string
  13. $s2 = @'
  14. using System;
  15. public class CLA
  16. {
  17. string FUN1()
  18. {
  19. return "FUN1";
  20. }
  21. }
  22. '@
  23. #--------------------------------------------------------------------情况3: 加了修饰词 public
  24. $s3 = @'
  25. using System;
  26. public class CLA
  27. {
  28. public void FUN1()
  29. {
  30. Console.WriteLine("FUN1");
  31. }
  32. }
  33. '@
  34. #--------------------------------------------------------------------情况4: 加了修饰词 public static
  35. $s4 = @'
  36. using System;
  37. public class CLA
  38. {
  39. public static string FUN1()
  40. {
  41. return "FUN1";
  42. }
  43. }
  44. '@
  45. # 使用正则表达式删除指定函数
  46. $s1 -replace '(?s)void\s+FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}'
  47. $s2 -replace '(?s)string\s+FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}'
  48. $s3 -replace '(?s)public void\s+FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}'
  49. $s4 -replace '(?s)public static string\s+FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}'
复制代码

作者: idwma    时间: 2023-5-9 17:57

回复 4# 小白龙
  1. .*FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}
复制代码

作者: 小白龙    时间: 2023-5-9 18:46

回复 6# idwma


    多谢大佬, 这个正则可以适应各种情况, 但是必须关闭单行模式才有效, 前面的正则式必须开单行, 为什么这么大差别呢?
作者: 小白龙    时间: 2023-5-9 18:48

回复 6# idwma


   下面两个需求, 怎样在上面正则的基础上修改? 搞不太懂, 问了几次chatgpt, 答非所问

# 需求2 用正则表达式: 修改指定函数名前的修饰词(不要修改返回值类型)
#例如: 把 FUN1 函数的修饰词改为 public static (如果没有修饰词就加上,如果有就修改)

# 需求3 用正则表达式: 修改指定类名前的修饰词
#例如: 把 CLA 类的修饰词改为 private (如果没有修饰词就加上,如果有就修改)
作者: idwma    时间: 2023-5-9 20:19

  1. $s1 -replace '.*(FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','public static $1'
  2. $s1 -replace '.*(CLA\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','private $1'
复制代码

作者: idwma    时间: 2023-5-9 20:26

回复 7# 小白龙


    不知道
作者: 小白龙    时间: 2023-5-10 07:31

本帖最后由 小白龙 于 2023-5-10 07:33 编辑

回复 9# idwma
  1. $s1 -replace '.*(FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','public static $1'
复制代码
用上面的正则会删除函数的返回值类型,  返回值类型也有很多种, 不固定, 下面示例中红色字是添加的修饰词, 其后蓝色字是返回值类型,不应修改
修改前
public class CLA
{
        void FUN1()
        {
                Console.WriteLine("FUN1");
        }
}
修改后
public class CLA
{
        public static void FUN1()
        {
                Console.WriteLine("FUN1");
        }
}
作者: 小白龙    时间: 2023-5-10 07:40

本帖最后由 小白龙 于 2023-5-10 07:53 编辑

回复 9# idwma


    返回值类型有下面几种, 都在函数名前, 除了第2个在括号中有空格之外, 其它的情况都是个整体, 内部没有空格, 这个好像有点难度了, 问gpt 完全不知道在说什么
int? GetNullableInt()
(string, int) GetPersonInfo()
IEnumerable<int> GetNumbers()
async Task<string> DownloadFileAsync(string url)
  1. // 返回Nullable类型
  2. int? GetNullableInt()
  3. {
  4.     int? result = null;
  5.     return result;
  6. }
  7. // 返回Tuple类型
  8. (string, int) GetPersonInfo()
  9. {
  10.     string name = "张三";
  11.     int age = 20;
  12.     return (name, age);
  13. }
  14. // 返回IEnumerable类型
  15. IEnumerable<int> GetNumbers()
  16. {
  17.     yield return 1;
  18.     yield return 2;
  19.     yield return 3;
  20. }
  21. // 返回Task类型
  22. async Task<string> DownloadFileAsync(string url)
  23. {
  24.     HttpClient client = new HttpClient();
  25.     HttpResponseMessage response = await client.GetAsync(url);
  26.     string content = await response.Content.ReadAsStringAsync();
  27.     return content;
  28. }
复制代码

作者: idwma    时间: 2023-5-10 10:40

本帖最后由 idwma 于 2023-5-10 11:33 编辑

回复 12# 小白龙

是这样吗
  1. $s1 -replace '(?<a>\s*)(private|public|static|async|(?<b>(string|void|int\?|\(string, int\)|IEnumerable<int>|Task<string>)\s*)|\s*)*(?<c>FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','${a}public static ${b}${c}'
复制代码
再试试这样
  1. $s1 -replace '(?<a>\s*)(private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*)|\s*)*(?<c>FUN1\s*\(\s*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','${a}public static ${b}${c}'
复制代码

作者: 小白龙    时间: 2023-5-10 13:07

回复 13# idwma

多谢大佬, 这种具体限定几个关键字有个问题, 就是返回值类型还有很多, 例如  string[]
但是有个总规律:

函数名前都有一个空格

情况1. 空格前如果是个关括号 ) 则匹配的开括号( 这中间允许有空格, 像下面这样
(string, int) GetPersonInfo()

情况2.空格前都是连续的, 没有空格, 像#12楼的例子
就这两种情况
作者: idwma    时间: 2023-5-10 13:29

回复 14# 小白龙


    试试13楼的第二个,只用指定修饰符应该没多少个缺的自己加上去
作者: 小白龙    时间: 2023-5-10 16:20

回复 15# idwma

我测试的这个函数,
DownloadFileAsync
, 一直运行, 停不下来了, 我就改了下面两个红色字的地方
(?<a>\s*)(private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*)|\s*)*(?<c>DownloadFileAsync\s*\(.*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})', '${a}public static ${b}${c}
  1. $s = @'
  2. // 返回Nullable类型
  3. int? GetNullableInt()
  4. {
  5.     int? result = null;
  6.     return result;
  7. }
  8. // 返回Tuple类型
  9. (string, int) GetPersonInfo()
  10. {
  11.     string name = "张三";
  12.     int age = 20;
  13.     return (name, age);
  14. }
  15. // 返回IEnumerable类型
  16. IEnumerable<int> GetNumbers()
  17. {
  18.     yield return 1;
  19.     yield return 2;
  20.     yield return 3;
  21. }
  22. // 返回Task类型
  23. async Task<string> DownloadFileAsync(string url)
  24. {
  25.     HttpClient client = new HttpClient();
  26.     HttpResponseMessage response = await client.GetAsync(url);
  27.     string content = await response.Content.ReadAsStringAsync();
  28.     return content;
  29. }
  30. '@
  31. $s -replace '(?<a>\s*)(private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*)|\s*)*(?<c>DownloadFileAsync\s*\(.*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})', '${a}public static ${b}${c}'
复制代码

作者: idwma    时间: 2023-5-10 16:58

回复 16# 小白龙
  1. $s -replace '(?<a>\n\s*)(private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*))*(?<c>DownloadFileAsync\s*\([^)]*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})','${a}public static ${b}${c}'
复制代码

作者: 小白龙    时间: 2023-5-10 17:12

回复 17# idwma


    那个函数修改可以了, 我把正则中的函数名改为另一个  IEnumerable<int>  测试没有效果
作者: idwma    时间: 2023-5-10 17:16

回复 18# 小白龙


    把你改的发出来看看
作者: 小白龙    时间: 2023-5-10 17:34

回复 19# idwma
  1. $s = @'
  2. // 返回Nullable类型
  3. // 返回IEnumerable类型
  4. IEnumerable<int> GetNumbers()
  5. {
  6.     yield return 1;
  7.     yield return 2;
  8.     yield return 3;
  9. }
  10. '@
  11. $s -replace '(?<a>\s*)(private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*)|\s*)*(?<c>GetNumbers\s*\(.*\)\s*\{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\})', '${a}public static ${b}${c}'
复制代码

作者: 小白龙    时间: 2023-5-10 17:38

回复 19# idwma


    我让gpt写了一下注释
  1. $s -replace '(?x) # 开启忽略空格和注释选项
  2. (?<a>\n\s*) # 匹配换行符和空格并捕获到名为"a"的组中
  3. (private|public|static|async|(?<b>(\b\S+|\([^()]+\))\s*))*
  4. # 匹配访问修饰符和方法类型,并将它们捕获到名为"b"的组中
  5. (?<c> # 匹配方法名和参数列表,并将其捕获到名为"c"的组中
  6. DownloadFileAsync\s* # 匹配方法名
  7. \([^)]*\)\s* # 匹配参数列表
  8. \{(?:[^{}]+|\{(?<DEPTH>)|\}(?<-DEPTH>))*?(?(DEPTH)(?!))\}
  9. # 匹配方法体
  10. )',
  11. '${a}public static ${b}${c}' # 将匹配到的代码块替换为公共静态方法,并确保代码可执行
复制代码

作者: idwma    时间: 2023-5-10 17:43

回复 20# 小白龙


    再看看17楼




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2