【问题标题】:Regex find all occurrences of a pattern in a string正则表达式在字符串中查找所有出现的模式
【发布时间】:2013-07-10 18:55:13
【问题描述】:

我在查找字符串中出现的所有模式时遇到问题。

检查这个字符串:

string msg= "=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?= =?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?=";

我想返回 2 次出现(以便稍后解码):

=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?=

=?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?="

使用以下正则表达式代码,它仅返回 1 次:完整字符串。

var charSetOccurences = new Regex(@"=\?.*\?B\?.*\?=", RegexOptions.IgnoreCase);
var charSetMatches = charSetOccurences.Matches(input);
foreach (Match match in charSetMatches)
{
    charSet = match.Groups[0].Value.Replace("=?", "").Replace("?B?", "").Replace("?b?", "");
}

你知道我错过了什么吗?

【问题讨论】:

  • 据我所知,你可以通过在空格上拆分字符串来获得两次出现,对吧?
  • 请问“windows-”和“?B”之间的字符?总是数字?

标签: c# .net regex


【解决方案1】:

regexp 解析器看到.* 字符序列时,它会匹配到字符串末尾的所有内容,然后逐个字符地返回(贪婪匹配)。因此,为避免该问题,您可以使用非贪婪匹配或显式定义可出现在字符串中的字符。

"=\?[a-zA-Z0-9?=-]*\?B\?[a-zA-Z0-9?=-]*\?="

【讨论】:

  • +1 可能有点限制,但适用于给定的数据集
【解决方案2】:

一种非正则表达式方式:

string msg= "=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?= =?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?=";
string[] charSetOccurences = msg.Split(new string[]{ " " }, StringSplitOptions.None);
foreach (string s in charSetOccurences)
{
    string charSet = s.Replace("=?", "").Replace("?B?", "").Replace("?b?", "");
    Console.WriteLine(charSet);
}

查看ideone

如果您仍想使用正则表达式,您应该通过添加 ? 来使 .* 变得懒惰。以前的用户已经提到过,但是您似乎没有得到匹配?

string msg= "=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?= =?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?=";
var charSetOccurences = new Regex(@"=\?.*?\?B\?.*?\?=", RegexOptions.IgnoreCase);
var charSetMatches = charSetOccurences.Matches(msg);
foreach (Match match in charSetMatches)
{
    string charSet = match.Groups[0].Value.Replace("=?", "").Replace("?B?", "").Replace("?b?", "");
    Console.WriteLine(charSet);
}

查看另一个ideone

两种情况下的输出是一样的:

windows-1258UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?=
windows-1258IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=

编辑:根据更新,查看针对您的问题的多合一解决方案

string msg= "=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?= =?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?=";
var charSetOccurences = new Regex(@"=\?.*?\?[BQ]\?.*?\?=", RegexOptions.IgnoreCase);
MatchCollection matches = charSetOccurences.Matches(msg);
foreach (Match match in matches)
{
    string[] encoding = match.Groups[0].Value.Split(new string[]{ "?" }, StringSplitOptions.None);
    string charSet = encoding[1];
    string encodeType = encoding[2];
    string encodedString = encoding[3];
    Console.WriteLine("Charset: " + charSet);
    Console.WriteLine("Encoding type: " + encodeType);
    Console.WriteLine("Encoded String: " + encodedString + "\n");
}

返回:

Charset: windows-1258
Encoding type: B
Encoded String: UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz

Charset: windows-1258
Encoding type: B
Encoded String: IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=

this

或者既然我们已经有了正则表达式,我们可以使用:

string msg= "=?windows-1258?B?UkU6IFRyIDogUGxhbiBkZSBjb250aW51aXTpIGQnYWN0aXZpdOkgZGVz?= =?windows-1258?B?IHNlcnZldXJzIFdlYiBHb1ZveWFnZXN=?=";
var charSetOccurences = new Regex(@"=\?(.*?)\?([BQ])\?(.*?)\?=", RegexOptions.IgnoreCase);
MatchCollection matches = charSetOccurences.Matches(msg);
foreach (Match match in matches)
{
    Console.WriteLine("Charset: " + match.Groups[1].Value);
    Console.WriteLine("Encoding type: " + match.Groups[2].Value);
    Console.WriteLine("Encoded String: " + match.Groups[3].Value + "\n");
}

Returns the same output.

【讨论】:

  • 当我解码一封电子邮件时,第一个字符串被编码,第二个是“纯文本”。示例:=?Windows-1252?Q?Fr=E9d=E9ric_Gerard?= 。因此,应该只有一个匹配项,即第一个将进入解码函数的字符串。正则表达式似乎是仅提取编码模式的最佳候选者
  • @CloudAnywhere 这个编码的字符串将不会被匹配,因为中间没有?B?。你也想匹配吗?你还有哪些可能,或者只要以=?开头并以?=结尾都无所谓?
  • 我知道,我们正在处理大量编码。我为此尝试的正则表达式是 @"\=\?Windows-1252\?Q\?.*\?\=" 。但问题是一样的:我只需要返回已编码的模式以将它们发送到解码函数。
  • @CloudAnywhere,如果您有更多信息,请将其放在您的问题中,而不是在 cmets 中,这样每个人都会看到。
  • @CloudAnywhere 你有问题。如果您要为每个案例场景使用一个正则表达式,那么您做得不好......
【解决方案3】:

.* 是贪心的,会匹配从第一个 ? 到最后一个 ?B? 的所有内容。

您需要使用非贪婪匹配

=\?.*?\?B\?.*?\?=

或从您的字符列表中排除 ?

=\?[^?]*\?B\?[^?]*\?=

【讨论】:

  • 两个命题都返回 0 匹配。
猜你喜欢
  • 2022-06-28
  • 1970-01-01
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
相关资源
最近更新 更多