3

试图提出一个“简单”的正则表达式来屏蔽看起来可能包含帐号的文本位。

用简单的英语:

  • 任何包含数字的单词(或一串这样的单词)都应该匹配
  • 保留最后 4 位数字不变
  • 用四个 X (xxxx) 替换匹配字符串的所有先前部分

至今

我正在使用以下内容:

[\-0-9 ]+(?<m1>[\-0-9]{4})

替换为

xxxx${m1}

但这错过了下面的最后几个样本

样本数据:

123456789
a123b456
a1234b5678
a1234 b5678
111 22 3333
this is a a1234 b5678 test string

实际结果

xxxx6789
a123b456
a1234b5678
a1234 b5678
xxxx3333
this is a a1234 b5678 test string

预期成绩

xxxx6789
xxxxb456
xxxx5678
xxxx5678
xxxx3333
this is a xxxx5678 test string

用正则表达式替换这样的安排是否可行?

我认为我将需要一些贪婪和前瞻功能,但我在这些领域的经验为零。

4

4 回答 4

3

这适用于您的示例:

var result = Regex.Replace(
    input,
    @"(?<!\b\w*\d\w*)(?<m1>\s?\b\w*\d\w*)+",
    m => "xxxx" + m.Value.Substring(Math.Max(0, m.Value.Length - 4)));

如果您有类似的值111 2233 33,它将打印xxxx3 33。如果您希望它没有空格,您可以将 lambda 转换为从值中删除空格的多行语句。

为了稍微解释一下正则表达式模式,它有一个否定的后视,所以它确保它后面的单词没有数字(数字周围有可选的单词字符)。然后它得到了m1部分,它在其中查找带有数字的单词。在正则表达式模式解析其余字符后,通过一些 C# 代码获取最后四个字符。

于 2013-11-04T19:41:54.323 回答
2

你有没有试过这个:

.*(?<m1>[\d]{4})(?<m2>.*)

带替换

xxxx${m1}${m2}

这产生

xxxx6789
xxxx5678
xxxx5678
xxxx3333
xxxx5678 test string

你不会得到'a123b456'来匹配......直到'b'变成一个数字。;-)

于 2013-11-04T19:38:42.147 回答
2

我不认为正则表达式是解决这个问题的最佳方法,这就是我发布这个答案的原因。对于如此复杂的情况,构建相应的正则表达式太难了,更糟糕的是,它的清晰度和适应性远低于较长代码的方法。

这些行下面的代码提供了您所追求的确切功能,它足够清晰并且可以轻松扩展。

string input = "this is a a1234 b5678 test string";
string output = "";
string[] temp = input.Trim().Split(' ');
bool previousNum = false;
string tempOutput = "";
foreach (string word in temp)
{
    if (word.ToCharArray().Where(x => char.IsDigit(x)).Count() > 0)
    {
        previousNum = true;
        tempOutput = tempOutput + word;
    }
    else
    {
        if (previousNum)
        {
            if (tempOutput.Length >= 4) tempOutput = "xxxx" + tempOutput.Substring(tempOutput.Length - 4, 4);
            output = output + " " + tempOutput;
            previousNum = false;
        }
        output = output + " " + word;
    }
}
if (previousNum)
{
    if (tempOutput.Length >= 4) tempOutput = "xxxx" + tempOutput.Substring(tempOutput.Length - 4, 4);
    output = output + " " + tempOutput;
    previousNum = false;
}
于 2013-11-04T19:59:14.160 回答
1

这是我非常快速的尝试:

(\s|^)([a-z]*\d+[a-z,0-9]+\s)+

这将选择所有这些测试用例。现在对于 C# 代码,您需要检查每个匹配项以查看匹配序列的开头或结尾是否有空格(例如,最后一个示例将在选中前后有空格)

这是进行替换的 C# 代码:

var redacted = Regex.Replace(record, @"(\s|^)([a-z]*\d+[a-z,0-9]+\s)+",
    match => "xxxx" /*new String("x",match.Value.Length - 4)*/ + 
    match.Value.Substring(Math.Max(0, match.Value.Length - 4)));
于 2013-11-04T19:39:55.377 回答