【问题标题】:Extracting a Substring when the string to find has varying whitespaces当要查找的字符串具有不同的空格时提取子字符串
【发布时间】:2020-08-05 04:52:01
【问题描述】:

我有一个像下面这样的字符串。

传真:666-111-2222 电话号码:200100200

我想找到电话号码。但问题是,Phone 之后和 # 之后的空格数在不同的字符串中可能会有所不同,以从中提取数据。另外,不建议编写复杂的函数,因为我有一个大数据集可以从中提取数据。

我尝试了下面的代码,它给了我正确的起始索引和 n 个空格。但我找不到之后的位置:从那

System.Globalization.CultureInfo.InvariantCulture.CompareInfo.IndexOf(FullString,"Phone#:",System.Globalization.CompareOptions.IgnoreSymbols)

【问题讨论】:

  • 请发布足够数量的源数据行,以便我们可以看到您要解析的字符串的所有可能格式。
  • 您只是想定位或提取号码?

标签: c# string vb.net substring indexof


【解决方案1】:

这显然是正则表达式的工作。

String toMatch = "Fax : 666-111-2222 Phone # : 200100200";
Regex matchPhone = new Regex("\\bPhone\\s*#\\s*:\\s*");
MatchCollection matches = matchPhone.Matches(toMatch);
foreach (Match match in matches)
{
    Int32 position = match.Index + match.Length;
    // do whatever you want with the result here
}

在代码中,反斜杠加倍,但实际的正则表达式是:

\bPhone\s*#\s*:\s*

  • \b 表示词的边界,意思是词的开始或结束。这也可以防止“MegaPhone”之类的内容匹配。
  • \s 表示任何类型的空格。这匹配空格、制表符和换行符。
  • * 表示零次或多次重复,意思是,如果空格根本不存在,或者有一百个空格长,它仍然会匹配。

请注意,这只会为您提供给定字符串中所有找到的电话号码的开始的索引。您没有指定是否有任何特定的方法来检测电话号码的 end,或者即使它们有任何特定的预期格式,所以不包括在内。如果您希望这样做,并且您不知道此电话号码后面可能出现的确切内容,请查看正则表达式字符组和匹配的特定数字内容,然后使用捕获组从匹配的内容中提取它。

如果整个字符串中只有一个匹配项,则可以使用

String toMatch = "Fax : 666-111-2222 Phone # : 200100200";
Regex matchPhone = new Regex("\\bPhone\\s*#\\s*:\\s*");
Match match = matchPhone.Match(toMatch);
Int32 position = match.Index + match.Length;

【讨论】:

  • 为什么不只是\d+$(或\d+$(?<=\d))?似乎该数字位于行尾。所以你可以只拥有string number = Regex.Match(input, @"\d+$").Value;
  • (?>Phone\D+)(\d+) 可能更快。
  • 我会避免使用\d,直到我们从 OP 那里得到更清晰的信息。电话号码很少只是数字。
  • 正如 Enigmativity 所说,我没有添加该部分,因为问题中没有明确说明。事实上,我在回答中也说过这一点。
  • 如你所见,我没有在评论前加上你的昵称。不完全适合你。它针对 OP:缺少真正的规范,因此,在任何情况下,正则表达式都可以引入不需要的东西或遗漏一些东西。
【解决方案2】:

Phone 和 # 之间有空格,# 和 : 之间也有空格。具有单个参数的子字符串将返回从该索引到输入字符串末尾的字符串。 Trim 将删除两边的所有空格。

Private Function GetPhone(input As String) As String
    Dim i = input.IndexOf("Phone")
    Dim s = input.Substring(i)
    Dim splits = s.Split(":"c)
    Return splits(1).Trim
End Function

我运行函数 10,000 次,耗时 5 毫秒。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim s = "Fax: 666-111-2222 Phone # : 200100200"
    Dim Phone As String = ""
    Dim sw As New Stopwatch
    sw.Start()
    For i = 0 To 10_000
        Phone = GetPhone(s)
    Next
    sw.Stop()
    Debug.Print(sw.ElapsedMilliseconds.ToString)
    MessageBox.Show(Phone)
End Sub

【讨论】:

  • 我说空格的数量会有所不同。
【解决方案3】:

我假设您需要 C# 答案。

我会使用正则表达式,但如果你坚持使用IndexOf,你可以这样做:

string fullString = "Fax : 666-111-2222 Phone # : 200100200";
int phonePos = fullString.IndexOf("Phone");
int hashPos = fullString.IndexOf("#", phonePos+"Phone".Length);
int colonPos = fullString.IndexOf(":", hashPos+1);

这样你就有了冒号的绝对位置,不管有多少空格。 请注意,我使用String.IndexOf。没有理由像您那样从 CompareInfo 中挖掘它。 另请注意,我使用带有额外参数的重载,即起始索引。

【讨论】:

  • 字符串中有数百个:
  • @PraveenVenu - 您需要在问题中明确指定输入数据。请不要将信息作为 cmets 添加到答案中。如果您的问题不清楚,请解决问题。
  • 字符串中有多少个冒号并不重要。代码在Phone之后找到#之后的第一个冒号。
【解决方案4】:

如果您可以依赖该格式,那就很简单了。 只需清除 all 空格 (.Replace(" ", string.Empty)) 的字符串,然后拆分电话号码开始的字符,例如"#:":

var phoneFull = @"Fax : 666-111-2222 Phone # : 200100200";
var phone = phoneFull
    .Replace(" ", string.Empty)
    .Split("#:")
    .Last();

【讨论】:

  • Option Strict 不允许.Split("#:")
  • 我使用的.Net版本只为StringSplitOptions提供了两个选项:NoneRemoveEmptyEntries
  • 抱歉,我想的是 vb.net。这不会在 C# 中编译。
  • 即使在 vb 中,也只会将“#:”解释为 Char 数组。您可以在 Option Strict 或 C# 中使用 "#:".ToCharArray() 获得相同的效果。
【解决方案5】:

我认为你应该使用正则表达式:

Regex rxPhone = new Regex(@"Phone\s*#\s*:\s*(\d+)");
Match match = rxPhone.Match(stringToMatch);
if (match.Success) //if the phone does not always exits
{
    string strPhoneNumber = match.Groups[1];
    int intPhoneNumber = int.Parse(match.Groups[1]);
    int position = match.Groups[1].Index
    //just pick the one you need
}

【讨论】:

  • 真实世界的电话号码仅由一系列\d 组成的可能性非常低。我认为 OP 选择了一个不好的例子。
猜你喜欢
  • 2019-11-19
  • 2012-10-24
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
相关资源
最近更新 更多