C# regex replace 详解

 

以下的分组构造捕获匹配的子表达式:

(子表达式)

其中子表达式为任何有效正则表达式模式。使用括号的捕获按正则表达式中左括号的顺序从一开始从左到右自动编号。捕获元素编号为零的捕获是由整个正则表达式模式匹配的文本。

命名匹配的子表达式

以下的分组构造捕获匹配的子表达式,并允许您按名称或数访问它:

(?<name>subexpression)

或:

(?'name' subexpression)
其中名称是有效的组名称,而子表达式是任何有效的正则表达式模式。 名称不得包含任何标点符号字符,并且不能以数字开头。

可用以下方式访问已命名的捕获组:

通过使用正则表达式中被命名的反向引用构造。使用语法 \k<name> 在同一正则表达式中引用匹配的子表达式,其中 name 是捕获子表达式的名称。

通过使用正则表达式中的反向引用构造。匹配的子表达式在相同的正则表达式中引用,方法是使用语法 \数字,其中数字是捕获的表达式的初始数字。已命名的匹配子表达式在匹配子表达式后从左到右连续编号。

通过使用 Regex.ReplaceMatch.Result 方法调用中的 ${名称} 替换顺序,其中名称为捕获的字表达式的名称。

通过使用 Regex.ReplaceMatch.Result 方法调用中的 $ 编号 > 替换序列,其中编号为捕获的子表达式的序号。

以编程的方式,通过使用 GroupCollection 对象的方式,该对象由 Match.Groups 属性返回。集合中位置零上的成员表示正则表达式匹配。每个后续成员表示匹配的子表达式。已命名的捕获组在集合中存储在已编号的捕获组后面。

以编程方式,通过提供子表达式至 GroupCollection 对象的索引器(以 C#),或者至其 Item 属性(以 Visual Basic)的方式。

简单的正则表达式模式会阐释如何编号(未命名),并且可以以编程方式或通过正则表达式语言语法引用已命名的组。正则表达式 ((?<One>abc)\d+)?(?<Two>xyz)(.*) 按编号和名称产生下列捕获组。编号为 0 的第一个捕获组总是指整个模式。

   

0

0(默认名称)

((?<One>abc)\d+)?(?<Two>xyz)(.*)

1

1(默认名称)

((?<One>abc)\d+)

2

2(默认名称)

(.*)

3

One

(?<One>abc)

4

2

(?<Two>xyz)

 Regex.Replace 方法 (String, String)

在指定的输入字符串内,使用指定的替换字符串替换与某个正则表达式模式匹配的所有字符串。

命名空间:  System.Text.RegularExpressions
程序集:  System(在 System.dll 中)
public string Replace(
 string input,
 string replacement
)

参数 input类型: System.String
要搜索匹配项的字符串。
replacement类型: System.String
替换字符串。
返回值类型: System.String
一个与输入字符串基本相同的新字符串,唯一的差别在于,其中的每个匹配字符串已被替换字符串代替。

备注
 

对匹配项的搜索从 input 字符串的开头处开始。该正则表达式采用由当前 Regex 对象的构造函数定义的模式。

replacement 参数指定字符串,该字符串代替 input 中的每个匹配项。replacement 可包括文本和替换的任何组合。例如,替换模式 a*${test}b 会插入字符串“a*”,该字符串后跟按 test 捕获组匹配的子字符串,该子字符串后跟字符串“b”(如果有)。在替换模式中 * 字符不被识别为元字符

注意

替换是替换模式中识别的唯一的正则表达式语言元素。所有其他正则表达式语言元素,包括字符转义,仅在正则表达式模式中允许,在替换模式中不会被识别。

 


using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "This is   text with   far  too   much   " +
                     "whitespace.";
      string pattern = "\\s+";
      string replacement = " ";
      Regex rgx = new Regex(pattern);
      string result = rgx.Replace(input, replacement);

      Console.WriteLine("Original String: {0}", input);
      Console.WriteLine("Replacement String: {0}", result);                            
   }
}
// The example displays the following output:
//       Original String: This is   text with   far  too   much   whitespace.
//       Replacement String: This is text with far too much whitespace.

 


using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern =  @"(\p{Sc}\s?)?(\d+\.?((?<=\.)\d+)?)(?(1)|\s?\p{Sc})?";
      string input = "$17.43  â‚2 16.33  £0.98  0.43   £43   12â‚  17";
      string replacement = "$2";
      Regex rgx = new Regex(pattern);
      string result = rgx.Replace(input, replacement);

      Console.WriteLine("Original String:    '{0}'", input);
      Console.WriteLine("Replacement String: '{0}'", result);                            
   }
}
// The example displays the following output:
//    Original String:    '$17.43  â‚2 16.33  £0.98  0.43   £43   12â‚   17'
//    Replacement String: '17.43  2 16.33  0.98  0.43   43   12  17'

 

Regex.Replace 方法 (String, String, String)

在指定的输入字符串内,使用指定的替换字符串替换与指定正则表达式匹配的所有字符串。

命名空间:  System.Text.RegularExpressions
程序集:  System(在 System.dll 中)
public static string Replace(
 string input,
 string pattern,
 string replacement
)

参数 input类型: System.String
要搜索匹配项的字符串。
pattern类型: System.String
要匹配的正则表达式模式。
replacement类型: System.String
替换字符串。
返回值类型: System.String
一个与输入字符串基本相同的新字符串,唯一的差别在于,其中的每个匹配字符串已被替换字符串代替。

备注

静态 Replace 方法等效于使用指定的正则表达式模式构造 Regex 对象并调用实例方法 Replace。

pattern 参数由通过符号描述要匹配的字符串的各种正则表达式语言元素组成。有关正则表达式的更多信息,请参见 .NET Framework 正则表达式正则表达式语言元素。对匹配项的搜索从 input 字符串的开头处开始。

replacement 参数指定字符串,该字符串代替 input 中的每个匹配项。replacement 可包括文本和替换的任何组合。例如,替换模式 a*${test}b 会插入字符串“a*”,该字符串后跟按 test 捕获组匹配的子字符串,该子字符串后跟字符串“b”(如果有)。在替换模式中 * 字符不被识别为元字符。

注意
替换是替换模式中识别的唯一的正则表达式语言元素。所有其他正则表达式语言元素,包括字符转义,仅在正则表达式模式中允许,在替换模式中不会被识别。

示例
下面的示例定义一个正则表达式 \s+,该表达式与一个或多个白色空白字符匹配。替换字符串 " ",将其用单个空格字符代替。


using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "This is   text with   far  too   much   " +
                     "whitespace.";
      string pattern = "\\s+";
      string replacement = " ";
      string result = Regex.Replace(input, pattern, replacement);

      Console.WriteLine("Original String: {0}", input);
      Console.WriteLine("Replacement String: {0}", result);                            
   }
}
// The example displays the following output:
//       Original String: This is   text with   far  too   much   whitespace.
//       Replacement String: This is text with far too much whitespace.

下面的示例使用 Replace(String, String, String) 方法替换 UNC 路径以及本地文件路径中的本地计算机和驱动器名称。正则表达式使用 Environment.MachineName 属性包括本地计算机的名称,使用 Environment.GetLogicalDrives 方法包括逻辑驱动器的名称。要成功运行该示例,应替换文本字符串"MyMachine"与您的本地计算机名。


using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      // Get drives available on local computer and form into a single character expression.
      string[] drives = Environment.GetLogicalDrives();
      string driveNames = String.Empty;
      foreach (string drive in drives)
         driveNames += drive.Substring(0,1);
      // Create regular expression pattern dynamically based on local machine information.
      string pattern = @"\\\\(?i:" + Environment.MachineName + @")(?:\.\w+)*\\((?i:[" + driveNames + @"]))\$";

      string replacement = "$1:";
      string[] uncPaths = { @"\\MyMachine.domain1.mycompany.com\C$\ThingsToDo.txt",
                            @"\\MyMachine\c$\ThingsToDo.txt",
                            @"\\MyMachine\d$\documents\mydocument.docx" };

      foreach (string uncPath in uncPaths)
      {
         Console.WriteLine("Input string: " + uncPath);
         Console.WriteLine("Returned string: " + Regex.Replace(uncPath, pattern, replacement));
         Console.WriteLine();
      }
   }
}
// The example displays the following output if run on a machine whose name is
// MyMachine:
//    Input string: \\MyMachine.domain1.mycompany.com\C$\ThingsToTo.txt
//    Returned string: C:\ThingsToDo.txt
//   
//    Input string: \\MyMachine\c$\ThingsToDo.txt
//    Returned string: c:\ThingsToDo.txt
//   
//    Input string: \\MyMachine\d$\documents\mydocument.docx
//    Returned string: d:\documents\mydocument.docx

此正则表达式模式由下面的表达式定义:

"\\\\(?i:" + Environment.MachineName + ")(?:\. \w+)*\\((?i:[" + driveNames + "]))\$"

下表演示了如何解释正则表达式模式。

  

\\\\

匹配两个连续反斜杠 (\) 字符。因为反斜杠字符被解释为转义符,每个反斜杠必须由另一个反斜杠进行转义。

(?i:" + Environment.MachineName + ")

执行由Environment.MachineName属性返回的字符串的不区分大小写匹配。

(?:\. \w+)*

匹配句号 (.) 字符后跟一个或多个单词字符。此匹配可出现零次或多次。未捕获匹配的子表达式。

\\

匹配反斜杠 (\) 字符。

((?i:[" + driveNames + "]))

执行由各个盘符组成的字符类的不分大小写匹配。此匹配是捕获的第一个子表达式。

\$

匹配文本的美元符号 ($) 字符。

替换模式$1取代了整场比赛的第一次捕获子表达式。这就是它 UNC 机和驱动器名称替换的驱动器号。

关于Regex.Replace (String, String, String,RegexOptions) 方法

      今天使用这个方法碰到了一些意外,于是就查了下资料,做了些测试,发现自己以前的理解有误.
Regex.Replace (String input, String pattern, String replacement,RegexOptions) 方法

这个方法作用是用 replacement 来替换 input中符合pattern的部分,举例如下:
input: http://www.xxx.com/news/5/
replacement: /news.aspx
pattern: http://(.*/?) .*xxx.com/news/( d+)/*
因为input 中匹配的部分为 http://www.xxx.com/news/5/,按规则我们用/news.aspx来替换.
结果为: /news.aspx

同样:
input:  abcedft http://www.xxx.com/news/5/6/7YYYYY
replacement: /news.aspx
pattern: http://(.*?)\.*xxx.com/news/(\d+/)*(\d+)/*
结果为 abcedft/news.aspxYYYYY
因为input 中匹配的为 http://www.xxx.com/news/5/6/7

另外可以用$1,$2...来引用具体的匹配内容,如
input : http://www.xxx.com/news/5/
replacement: /news.aspx?c=$2
pattern: http://(.*?)\.*xxx.com/news/(\d+)/*
结果为/news.aspx?c=5

其中,$1,$2是应用的正则表达式中()里的内容

正则表达式(Regular expressions)是一套语法匹配规则,各种语言,如Perl, .Net和Java都有其对应的共享的正则表达式类库。在.Net中,这个类库叫做Regex。
简单的说,Regex是从字符窗中查找匹配字符串的应用类。通过Regex,编程人员能够非常方便的从一段数据中提取自己所需要的数据信息。举一个简单的例子,让大家对Regex有个大概的了解:
Regex regex = new Regex(@"d+");
Match m = regex.Match("fox 9212gold");
Console.WriteLine(m.Value.ToString());
结果很明显,regex为我们找到了字符串”fox 9212gold”中的数字字符串,输出结果为”9212” .
对Regex有了一个基本的概念之后,我需要告诉你一个非常好的消息,那就是Regex可以为我们做的远不止这么一点点,他是一套功能非常强大语法匹配规则。当然,这里还有一个坏消息等着我们,那就是强大功能的语法规则自然需要大量纷繁复杂的keyword支持,这也为Regex的学习带来了极大的难度。想要真正掌握正则表达式,可不是几个sample能够全部揭示与说明的。

创建一个Regex对象
Regex的构造函数有三种,在这里就不讨论默认构造函数了。另外两个构造函数中,一个构造函数接收正则表达式字符串作为入参,另一个以正则表达式字符串和RegexOptions作为入参。如:
 
Regex regex = new Regex("w+$");
Regex regex = new Regex("s+", RegexOptions.IgnoreCase | RegexOptions.Multiline);
RegexOptions可以为我们提供一些特殊的帮助,比如IgnoreCase能够在匹配是忽略大小写,Multiline能够调整^和$的意义,改为匹配一行的开头和结尾。
上面我们构造了一个正则表达式,只不过我们还没有用它来做任何事情,马上我们就可以通过使用下面的几个方法,实现对字符串对象的操作了。
匹配字符串
Regex有两个获取匹配的方法Match()和Matches(),分别代表匹配一个,匹配多个结果。这里就用Matches来展示一下怎么使用Regex获取匹配字符串,并将其显示出来。
 
组的概念

当你获得这样的一个字符串”最后比分是:19/24”,你肯定希望有一个正则表达式,他不单能够找到形如 data1/data2的字符串,还应该能够直接把data1,data2作为单独的结果传送出来。否则你需要再对形如”19/24”的字符串进行分析,才能够顺利得到双方的比分。显然,正则表达式不会忽略这个问题,所以他增加了组的概念。你可以把一次搜索的结果分别放入不同的组中,并通过组名或者组的所以分别取得这些组的结果。比如上例,我们就可以用@”(\d+)/(\d+)”作为表达式。来看看结果吧:
 
Regex regex = new Regex(@"(d+)/(d+)");
MatchCollection matches = regex.Matches(@"最后比分是:19/24");
//show matches
Console.WriteLine("----------------------------------");
foreach(Match m in matches)
{
//Console.WriteLine("match string is: "{0}", length: {1}", // m.Value.ToString(), m.Value.Length);
foreach(string name in regex.GetGroupNames())
{
Console.WriteLine("  capture group "{0}" value is:"{1}"" , name, m.Groups[name].Value);
}
}
Console.WriteLine("matched count: {0}", matches.Count);
输出:
----------------------------------
capture group "0" value is:"19/24"
capture group "1" value is:"19"
capture group "2" value is:"24"
matched count: 1

现在清楚了吧,Regex对象把匹配的结果放入组0中。同时,匹配的组信息也放入了对应的组中。组的名称在默认的情况下,是从1开始依次增加的整数。0作为保留名称,专门用于指示匹配的整个字符串。既然有”默认情况”这样的概念,自然也就意味着用户可以自定义组的名称。方法很简单,在组的前面加上:?<name>就可以了。好了,现在把前面的正则表达式修改一下,换成@”(?<score1>\d+)/(?<score1>\d+)”,现在再看看结果:
----------------------------------
capture group "0" value is:"19/24"
capture group "score1" value is:"19"
capture group "score2" value is:"24"
matched count: 1

换成自己定义的名字了吧,哈哈!为了在今后的测试中,能够更加方便的看到所有结果,我们对前面介绍过的showMatches()做一点小小的调整。这样,如果在表达式中包含了组的定义,我们也可以在不需要修改任何代码的情况下,直接看到所有的组信息了,调整后的方法showMatchesPro()如下:

public static void showMatchesPro(string expression, RegexOptions option, string ms)
{
Regex regex = new Regex(expression, option);
MatchCollection matches = regex.Matches(ms);
//show matches
Console.WriteLine("----------------------------------");
Console.WriteLine(" string: "{0}"  expression: "{1}"  match result is:",ms, expression);
foreach(Match m in matches)
{
  foreach(string name in regex.GetGroupNames())
{
Console.WriteLine("  capture group "{0}" value is:"{1}"",name, m.Groups[name].Value);
}
}
Console.WriteLine("matched count: {0}", matches.Count);
// show group name
Console.WriteLine("group name count {0}", regex.GetGroupNames().Length);
foreach(string name in regex.GetGroupNames())
{
Console.WriteLine("group name :"{0}"", name);
}
}
替换字符串
Regex也提供了方便的匹配结果替换的功能。为了方便测试,我们也把他写成方法,代码如下:

public static string replaceMatch(string expression, RegexOptions option, string ms, string rep)
{
Regex regex = new Regex(expression, option);
string result = regex.Replace(ms, rep);
Console.WriteLine("----------------------------------");
Console.WriteLine("string: "{0}", expression:"{1}", replace by : "{2}"", ms, expression, rep);
Console.WriteLine("replace result string is: "{0}", length: {1}", result.ToString(), result.Length);
return result;
}

Regex.Replace通常接受两个string作为入参,第一个string为输入字符串。第二个字符串用来替代匹配字符串,它可以包含一些特殊字符串,用来代表特别转换。

 

特殊字符串 替换结果
$& 匹配的字符串,也可以用$0
$1, $2, . . . 匹配字符串中的对应组,用索引标示
${name} 匹配字符串中的对应组,用名称标示
$‘ 匹配位置之前的字符串
$’ 匹配位置之后的字符串
$$ 一个‘$’ 字符
$_ 输入字符串
$+ 匹配字符串的所有组中,最后一个组中的数据

是不是看了这么多怪型怪状的特殊字符串,有点头晕了?嗯,那就弄两个sample来看看结果吧!
Sample1:
replaceMatch(@"\d+", RegexOptions.None, "fef 12/21 df 33/14 727/1", "<<$&>>");
输出,所有数字型的数据都被替换成了<<data>>:
----------------------------------
string: "fef 12/21 df 33/14 727/1", expression:"\d+", replace by : "<<$&>>"
replace result string is: "fef <<12>>/<<21>> df <<33>>/<<14>> <<727>>/<<1>>",
length: 50

Sample2:
replaceMatch(@"(\d+)/(\d+)", RegexOptions.None, "fef 12/21 df 33/14 727/1", "$+");
输出,所有data1/data2匹配的数据,都被替换成了data2:
----------------------------------
string: "fef 12/21 df 33/14 727/1", expression:"(\d+)/(\d+)", replace by : "$+"
replace result string is: "fef 21 df 14 1", length: 16

怎么样,Regex的功能够丰富的吧!可是,也许你的需求不光这么简单,比如说,你要把”I have 200 dollars”中间的money加倍,怎么办?我晕倒,好像没有现成的东西可以用。没有关系,Regex还有更好的功能。它允许你自己定义转换公式。
 
using System.Text.RegularExpressions;
class RegularExpressions
{
static string CapText(Match m)
{
// Get the matched string.
string x = m.ToString();
// double this value
string result = (int.Parse(x) * 2).ToString();
return result;
}
static void Main()
{
string text = "i have 200 dollars";
string result = Regex.Replace(text, @"d+",new MatchEvaluator(RegularExpressions.CapText));
System.Console.WriteLine("result=[" + result + "]");
}
}
看看结果,太好了,我的钱真的变成了两倍!
但本文的目的是希望提供给大家一个方便好用的测试类,因此我们重载上面的repalceMatch方法,也允许自定义转换公式作为入参:

public static string replaceMatch(string expression, RegexOptions option, string ms,
MatchEvaluator evaluator)
{
Regex regex = new Regex(expression, option);
string result = regex.Replace(ms, evaluator);
Console.WriteLine("----------------------------------");
Console.WriteLine("string: "{0}", expression:"{1}", replace by a evaluator.", ms, expression);
Console.WriteLine("replace result string is: "{0}", length: {1}", result.ToString(), result.Length);
return result;
}
拆分字符串

Regex还提供了从匹配位置将字符串拆分的方法Split。这个方法同样具有多个重载,不过这些都不是重点,大家可以自己看文档。我们继续完成我们用于测试的方法:
public static void splitMatch(string expression, RegexOptions option, string ms)
{
Regex regex = new Regex(expression, option);
string[] result = regex.Split(ms);
Console.WriteLine("----------------------------------");
Console.WriteLine("string: "{0}", expression: "{1}", split result is:", ms, expression);
foreach(string m in result)
{
Console.WriteLine("splited string is: "{0}", length: {1}",m.ToString(), m.Length);
}
Console.WriteLine("splited count: {0}", result.Length);
}
代码简单,不多做解释。直接来一个smaple看看结果:
splitMatch(@"/",RegexOptions.None, "2004/4/25");
输出:
----------------------------------
string: "2004/4/25", expression: "/", split result is:
splited string is: "2004", length: 4
splited string is: "4", length: 1
splited string is: "25", length: 2
splited count: 3

这个文章的目的很简单:介绍Regex的几个主要功能(匹配、替换和拆分),并提供几个简单方便的测试函数。让你能够测试你对正则表达式的理解是否准确。

比如想要确认^$的作用,你可以放入这样的(input, expression)数据:
(“123”, “^\d+$”) (“123aaa456”, “^\d+”) (“123aaa456”, “123&”)

确认\d, \s, \w, \W的作用,可以这样测试:
(“123abc gc 456”, “\d+”)(“123abc gc 456”, “\s+”)
(“123abc gc 456”, “\w+”)(“123abc gc 456”, “\W+”)

比较? + *之间的区别可以用这样的数据:
(“a123 abcd”, “a\d?”) (“a123 abcd”, “a\d+”) (“a123 abcd”, “a\d*”)



程序代码

string txt = "五千二百一十一";
string pattern = "([零一二三四五六七八九])[十百千万亿]([零一二三四五六七八九])";
Console.WriteLine(Regex.Replace(txt, pattern, "$1$2", RegexOptions.IgnoreCase));


上边例子的结果为"五二百一一",而不是我的期望"五二一一",为什么呢?我们再来看一个例子:

程序代码
string txt = "五千二百一十一";
string pattern = "([零一二三四五六七八九])[十百千万亿]([零一二三四五六七八九])";
MatchCollection matchs = Regex.Matches(txt, pattern, RegexOptions.IgnoreCase);
foreach (Match match in matchs)
    Console.WriteLine(match.Value);


结果:

引用内容
五千二
一十一



也就是说,我们无法使用上边的代码对"二百一"进行替换。修改后正确的代码:

程序代码
string txt = "五千二百一十一";
string pattern = "([零一二三四五六七八九])[十百千万亿]([零一二三四五六七八九])";
while (Regex.IsMatch(txt, pattern, RegexOptions.IgnoreCase))
    txt = Regex.Replace(txt, pattern, "$1$2", RegexOptions.IgnoreCase);
Console.WriteLine(txt);

C#正则表达式(RegEx)高级应用之分组(Group)替换(Replace)
 
对于复杂的、符合一定规则的字符串替换来说,正则表达式无疑是强悍和高效的选择

对于正则表达式的使用,我也写过几篇帖子了,具体可以见下面的地址

http://zu14.cn/tag/regex/

今天,说一下 .NET 里面 正则 使用的稍微高级一些的技巧:分组替换 ,下面我们举两个实例来说明这个问题:

一段字符串,把其中出现的 Ax,Ay 形式的内容,替换为 Ax 的形式(也就是 ,和Ay 都不要了),其中x 和y是数字,位长是 1~2,并且不会出现连排的形式

对于上面的需求,我们进行分析后,可以得出:上面的匹配规则,分为2组,(Ax) 一组,(,Ay) 一组 匹配后,直接返回第一组就OK了

对于.NET来说,分组替换的实现,有多种方式,我这里展示其中的2种,对于上面的例子,我使用 MatchEvaluator 方式

static string CustomReplace(System.Text.RegularExpressions.Match m)
{
return m.Groups[1].Value; //直接返回分组1
}

string sourceString = ".....";
string pattern = @"(A\d{1,2})(,A\d{1,2})";
System.Text.RegularExpressions.MatchEvaluator myEvaluator = new System.Text.RegularExpressions.MatchEvaluator(CustomReplace);
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase| System.Text.RegularExpressions.RegexOptions.Multiline);

string resultString = reg.Replace(sourceString, myEvaluator);
一段HTML代码,是用来插入FLASH的,形式如: <embed width=”1000” src=”…” …></embed>

需求是需要对这个FLASH的代码进行自定义,将 宽度 替换为自定义的值

对于这个例子,我们使用分组号 $# 的方式来实现,#代表数字,经过分析,可以得出,将上面的内容,分为3组

string sourceString = "......";
string toWidth = "300"; //自定义的宽度
string pattern = "(<embed .+? width\\s{0,}=\\s{0,}\"{0,1})(\\d+)(\"{0,1})";
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
string resultString = reg.Replace(sourceString, "${1}" +

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值