在C#中解析字符串;有更简洁的方法吗?

5

C#, .NET 3.5

这让我感觉很丑陋,但我想不到其他的方法。

给定一个格式为“Joe Smith(jsmith)”(不带引号)的字符串,我想解析出括号内的'jsmith'字符串。我想到了以下方法:

private static string DecipherUserName( string user )
{
    if( !user.Contains( "(" ) )
        return user;

    int start = user.IndexOf( "(" );

    return user.Substring( start ).Replace( "(", string.Empty ).Replace( ")", string.Empty );
}

除了我对正则表达式的(不)健康厌恶之外,是否有更简单的方法来解析子字符串?

编辑: 为了澄清,要解析的字符串始终为:"Joe Smith(jsmith)"(不带引号)。

6个回答

20

正则表达式非常有用,如果你咬咬牙学下来,将会为自己省去很多烦恼。不用掌握全部知识,只需要基础部分就行。

一个可用的正则表达式是"\w+\((.*)\)" - jsmith 将在 Match.Groups[1] 中。

学习正则表达式的一种简单方法是找到一个网站,允许您输入正则表达式和一些文本,然后输出匹配结果...


没有明确要求括号中的用户名必须跟随一个没有空格的名称。"\(.*\)" 应该是足够的。 - James
正确的工具,但错误的正则表达式 - 你需要一个可以处理没有括号的用户的正则表达式。如果能做到这一点,我会给你投票 :-) - paxdiablo
诚然,我并没有真正追求过正则表达式,这主要是因为我很少需要它们,最终只会忘记我所学的内容。@詹姆斯等人 - 初始的正则表达式“(.*)”看起来相当不错(而且简单),符合我的意图。回到我的开发机器上时,我会试一试的。干杯! - Metro Smurf
值得注意的是:我接受了Pax提出的重构解决方案,而不是使用正则表达式的解决方案,因为我认为从长远来看,这将更易于维护,直到我掌握了更多关于正则表达式的知识。此外,对1000个姓名进行快速测试,正则表达式方案需要0.1165195毫秒,而字符串方案只需0.0077423毫秒。 - Metro Smurf
2
有些人遇到问题时,会想:“我知道,我可以使用正则表达式。”现在他们有两个问题了。- jwz - Binary Phile
显示剩余5条评论

9

您不需要进行第一次替换,因为您可以将“(”位置加1。

private static string DecipherUserName (string user) {           
    int start = user.IndexOf( "(" );
    if (start == -1)
        return user;
    return user.Substring (start+1).Replace( ")", string.Empty );
}

值得注意的是:我接受了Pax的重构方案,而不是提供的正则表达式解决方案,因为我认为从长远来看,这将更易于维护,直到我更熟悉正则表达式。此外,对1000个名称进行快速测试,正则表达式解决方案为0.1165195毫秒,而字符串解决方案为0.0077423毫秒。 - Metro Smurf
对于像这样简单的文本匹配,正则表达式通常较慢(尽管可以在循环中编译一次以获得额外速度)。它们的真正优势在于其对更复杂情况的表达能力(例如,允许在括号内添加或删除空格)。学习价值很大,所以请继续保持。 - paxdiablo

5

有点像黑客技巧...^^

return user.Substring(user.IndexOf('(') + 1).TrimEnd(')');

如果user不包含左括号,IndexOf()返回-1,我们加一得到零,SubString()返回整个字符串。除非用户名以右括号结尾,否则TrimEnd()没有任何效果。
如果user包含左括号,IndexOf()返回其索引,我们通过加一跳过左括号,并使用Substring()提取剩余的字符串。最后,使用TrimEnd()删除右括号。

这并不很好地反映了意图。 - Sedat Kapanoglu
有点小技巧... ^^ ;) - Daniel Brückner
我非常喜欢正则表达式,而且我更喜欢使用正则表达式的解决方案。但对于不了解的人来说,这是一个很好的一行代码,不会比“\w+((.*))”更令人困惑。 - Daniel Brückner

5
如果用户字符串总是以“Joe Smith(jsmith)”的形式出现,那么这将起作用。
private static string DecipherUserName(string user)
{
    string[] names = user.Split(new char[] {'(', ')'});
    return names.Length > 2 ? names[1] : user;
}

如果用户字符串始终为“Joe Smith(jsmith)”,则这将始终有效。

private static string DecipherUserName(string user)
{
    return "jsmith";
}

仅供幽默目的的第二条目录。

2
由于IndexOf函数在值不存在时会返回-1,因此您可以稍微改变一下做法...
private static string DecipherUserName( string user )
{           
   int start = user.IndexOf( "(" );

   if (start > -1)
   {
      return user.Substring( start ).Replace( "(", string.Empty ).Replace( ")", string.Empty );
   }
   else
   {
      return user;
   }
}

忘记了当值不存在时,IndexOf会返回-1。谢谢! - Metro Smurf

1

我会使用

int start=user.IndexOf('(');
if (start != -1) {
  end = user.IndexOf(')', start);
  return user.Substring(start+1,end-start-1);
} else
  return user;

但这只是一个表面上的变化:在IndexOf中使用字符会快一点,而使用Substring方法似乎更准确地表达了应该做什么(如果您有多个括号对,则该方法更加健壮...)

话虽如此,Daniel L的方法(使用String.Split)可能更简单(但无法很好地处理格式不正确的字符串,并且必须构造一个字符串数组)。

总之,我建议您克服对正则表达式的厌恶,因为这种情况正是它们的用途所在 :-) ...


@Martin - 嗯,这是一种(不)健康的厌恶感 (-_^) 你关于子字符串更具表现力的评论绝对是正确的。 - Metro Smurf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接