检查字符串是否包含无效字符?最聪明的方法是什么?

10

我想检查一些字符串是否包含非法字符。所谓非法字符是指不应该出现的字符。这些字符是什么?虽然可能不太重要,但重要的是如何实现以及如何最简单和最有效地实现(性能)。

假设我只想要包含'A-Z'、'空格'、'.'、'$'、'0-9'的字符串

如果我的字符串是 "HELLO STaCKOVERFLOW" => 非法,因为有个 'a' 字符。

那么怎么做呢?我可以创建一个List<char>,将所有不允许的字符放入其中,并使用此列表检查字符串。也许不是个好主意,因为要加入很多字符。但我可以创建一个包含所有允许字符的列表吗?然后呢?对于字符串中的每个字符,我都必须与List<char>进行比较吗?有没有聪明的代码可以解决这个问题?另一个问题:如果我要添加 A-Z 到List<char>中,我需要手动添加 25 个字符,但这些字符据我所知在 ASCII 表中的码值为 65-90,有没有更容易的方法添加它们?谢谢


1
你可以使用字符列表的想法,然后使用字符串的indexof来实现,或者使用正则表达式。 - Ademar
1
请在一个 Stack Overflow 的问题中只提出一个问题。如果你有两个问题,请分开提问成两个 Stack Overflow 问题。谢谢。 - O. R. Mapper
6个回答

21

你可以使用正则表达式来完成这个任务:

Regex r = new Regex("[^A-Z0-9.$ ]$");
if (r.IsMatch(SomeString)) {
    // validation failed
}

要创建一个由 A-Z 或者 0-9 组成的字符列表,你需要使用一个简单的循环:

for (char c = 'A'; c <= 'Z'; c++) {
    // c or c.ToString() depending on what you need
}

但是使用正则表达式的话,并不需要那样做 - 几乎所有的正则表达式引擎都能理解范围语法(A-Z)。


啊,这可能比比较列表要容易得多。好主意。 - silla
一个问题。不应该是if (!r.IsMatching(Something)) => 验证失败吗?因为如果匹配,验证就没问题了,对吧? - silla
1
不,正则表达式匹配的是字符串中包含任何一个不在 [A-Z0-9.$ ] 范围内的字符 - 这样更有效率,因为正则表达式引擎一旦找到这样的字符就可以停止匹配了。 - ThiefMaster
啊,我有点困惑,因为从来没有在C#中使用过正则表达式。所以正则表达式开头的'^'就像是"!"(不)的意思。 - silla
1
是的,它否定了字符类。 - ThiefMaster

0

如果你对正则表达式不是非常熟悉,那么在C#中还有另一种方法可以解决这个问题。下面是我编写的一个代码块,用于测试名为notifName的字符串变量:

var alphabet = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
var numbers = "0,1,2,3,4,5,6,7,8,9";
var specialChars = " ,(,),_,[,],!,*,-,.,+,-";
var validChars = (alphabet + "," + alphabet.ToUpper() + "," + numbers + "," + specialChars).Split(',');
for (int i = 0; i < notifName.Length; i++)
{
    if (Array.IndexOf(validChars, notifName[i].ToString()) < 0) {
        errorFound = $"Invalid character '{notifName[i]}' found in notification name.";
        break;
        }
}

您可以根据需要更改添加到数组中的字符。数组IndexOf方法是整个过程的关键。当然,如果您希望逗号有效,则需要选择不同的拆分字符。


0

评论次数不足,但我建议使用正则表达式方法。一个小注意点:您可能需要锚定输入字符串的两端,并且您至少需要匹配一个字符。因此(感谢ThiefMaster),这是我的正则表达式,用于验证简单算术计算器(加、减、乘、除)的用户输入:

Regex r = new Regex(@"^[0-9\.\-\+\*\/ ]+$");

0

我会选择正则表达式,但仍需要在这里补充我的意见,因为所有提出的非正则表达式解决方案在最坏情况下(字符串有效)都是O(MN),这对于宗教原因而言是令人厌恶的。

更何况LINQ提供了比嵌套循环更简单和更高效的解决方案:

var isInvalid = "The String To Test".Intersect("ALL_INVALID_CHARS").Any();

0
我刚刚编写了这样一个函数,并扩展了它,以限制需要时第一个和最后一个字符。原始函数仅检查字符串是否仅由有效字符组成,扩展函数添加了两个整数,用于跳过要检查的列表开头的有效字符数量和结尾的有效字符数量,在实践中,它只是简单地调用原始函数3次,在下面的示例中,它确保字符串以字母开头,不以下划线结尾。
StrChr(String, "_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
StrChrEx(String, "_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 11, 1));


BOOL __cdecl StrChr(CHAR* str, CHAR* chars)
{
 for (int s = 0; str[s] != 0; s++)
 {
     int c = 0;

    while (true)
    {
        if (chars[c] == 0)
        {
             return false;
        }
         else if (str[s] == chars[c])
         {
            break;
         }
        else
         {
            c++;
         }
     }
 }

return true;
}

BOOL __cdecl StrChrEx(CHAR* str, CHAR* chars, UINT excl_first, UINT excl_last)
{
char first[2]   = {str[0], 0};
char last[2]    = {str[strlen(str) - 1], 0};

if (!StrChr(str, chars))
{
    return false;
}

if (excl_first != 0)
{
    if (!StrChr(first, chars + excl_first))
    {
        return false;
    }
}

if (excl_last != 0)
{
    if (!StrChr(last, chars + excl_last))
    {
        return false;
    }
}

return true;
}

0
如果您正在使用C#,则可以轻松使用List和contains来完成此操作。您可以对单个字符(在字符串中)或多字符字符串执行相同的操作。
  var pn = "The String To ChecK";      
  var badStrings = new List<string>()
  {
  " ","\t","\n","\r"
  };
  foreach(var badString in badStrings)
  {
    if(pn.Contains(badString))
    {
     //Do something
    }
  }

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