【问题标题】:Get first occurence of a char from a string从字符串中获取第一次出现的字符
【发布时间】:2017-05-28 17:26:01
【问题描述】:

首先,我想指出,期望的结果是一个字符,而不是它的位置索引 (int)。
我试图让我的用户选择他们想要的日期格式,因此,我创建了 2 个组合框:comboBox_DateFormatDivider,用户在点、破折号和斜杠之间进行选择;和comboBox_DateFormat 用户选择日期格式。 comboBox_DateFormat 包含一个List<string> 如下:

_dateFormatsList = new List<string>()
{
    "d-M-yy (" + DateTime.Now.ToString("d-M-yy") + ")",
    "dd-M-yy (" + DateTime.Now.ToString("dd-M-yy") + ")",
    "d-MM-yy (" + DateTime.Now.ToString("d-MM-yy") + ")",
    "dd-MM-yy (" + DateTime.Now.ToString("dd-MM-yy") + ")",
    "d-M-yyyy (" + DateTime.Now.ToString("d-M-yyyy") + ")",
    "dd-M-yyyy (" + DateTime.Now.ToString("dd-M-yyyy") + ")",
    "d-MM-yyyy (" + DateTime.Now.ToString("d-MM-yyyy") + ")",
    "dd-MM-yyyy (" + DateTime.Now.ToString("dd-MM-yyyy") + ")",
    "yy-M-d (" + DateTime.Now.ToString("yy-M-d") + ")",
    "yy-M-dd (" + DateTime.Now.ToString("yy-M-dd") + ")",
    "yy-MM-d (" + DateTime.Now.ToString("yy-MM-d") + ")",
    "yy-MM-dd (" + DateTime.Now.ToString("yy-MM-dd") + ")",
    "yyyy-M-d (" + DateTime.Now.ToString("yyyy-M-d") + ")",
    "yyyy-M-dd (" + DateTime.Now.ToString("yyyy-M-dd") + ")",
    "yyyy-MM-d (" + DateTime.Now.ToString("yyyy-MM-d") + ")",
    "yyyy-MM-dd (" + DateTime.Now.ToString("yyyy-MM-dd") + ")"
};
comboBox_DateFormat.DataSource = _dateFormatsList;

当用户选择不同的分隔符时,它必须反映在另一个组合框中,因为DateFormat依赖于DateFormatDivider,所以它的内容必须在运行时改变。这是代码(和问题):

private void comboBox_DateFormatDivider_SelectedIndexChanged(object sender, EventArgs e)
{
    for (int i = 0; i < _dateFormatsList.Count; i++)
    {
        _dateFormatsList[i] = _dateFormatsList[i].Replace(_dateFormatsList[i].???.ToString(), comboBox_DateFormatDivider.SelectedText);
    }
}

选择的日期格式稍后会保存到数据库中,所以我想我还可以添加另一个字段来存储分隔符,但我不希望这样做。如您所见,上面的代码中包含???。所以,问题是:如何将这些问号替换为可以找到它包含的分隔符的代码?

【问题讨论】:

  • 您应该在初始化该列表之前执行DateTime now = DateTime.Now;,以避免出现DateTime.Now 的值在元素之间发生变化的情况。
  • 执行 Regex.Match 来找到相关的分隔符并添加逻辑,这不是很简单,使用类似 Regex.Match(Value,".*(?:-).*") 的东西就会给你替换的分隔符
  • 您也可以将格式字符串存储为"dd@mm@yyyy" 之类的内容,然后当您将其用于DateTime.ToString 时,将@ 字符替换为使用_dateFormatsList[i].Replace("@", _chosenSeparator) 选择的分隔符。
  • 拜托,拜托,请不要去正则表达式来解决这个问题! Abion47给了你一个很好的答案。
  • @swatsonpicken 正则表达式有什么问题?

标签: c# replace


【解决方案1】:

假设日期格式的分隔符数量是有限的,我将执行以下操作:

List<string> dividers = new List<string>{".","/","-"}

private void comboBox_DateFormatDivider_SelectedIndexChanged(object sender, EventArgs e)
{
    string currentSeparator = string.Empty;

     foreach(var s in dividers)
     {
     string pattern = @".*(?:\" + s + ").*";

        if(Regex.IsMatch(_dateFormatsList[0],pattern))
        {
          currentSeparator = s;
          break;    
         }    
     }
    for (int i = 0; i < _dateFormatsList.Count; i++)
    {
        _dateFormatsList[i] = _dateFormatsList[i].Replace(currentSeparator, comboBox_DateFormatDivider.SelectedText);
    }
}

编辑 1:

正则表达式说明:

以下是详细信息: ".*(?:\.).*", .* 表示任何字符出现 0 次或多次, ?: 指模式搜索匹配开始,它期望传递的字符(这里是“.”),(它被转义,以避免特殊字符,如.,*,?等)在所有数据中搜索它将在第一次出现时返回 true,否则返回 false。

编辑 2:

提供一个正则表达式潜力的例子,在_dateFormatsList中,你有多种日期格式,但是所有的解决方案,只要选择一个值来计算运算符,其他值呢,如果有数据呢损坏并且存在多个分隔符,以下代码将处理很多此类问题,并且可以通过更改模式进一步严格:

string pattern = @"^(?!\.\/)[\d]{1,4}[\-][\d]{1,2}[\-][\d]{1,4}$";

它代表所有包含分隔符-但不包含./的日期格式,在分隔符-之前还有一个数字(\d)重复,此模式需要使用Linq应用@987654328 @运算符如下:

bool result = _dateFormatsList.All(data => Regex.IsMatch(data,pattern));

这只是为了描述正则表达式的强大功能,这是其他解决方案无法帮助实现的,我想大多数人会因为对模式创建缺乏了解而发现正则表达式很复杂

【讨论】:

  • 再一次,比它需要的复杂得多。
  • 指出复杂性,告诉我哪里可以更简单
  • 复杂性在于使用正则表达式。如果对设计稍作调整,就完全不需要进行字符串搜索了。看我的回答。
  • 我真的很喜欢这个解决方案,我可以在我的代码中简化foreach break 循环,并且我可以发表评论,解释正则表达式对可能不理解它的开发人员的作用。但是,为了我和后代,您能否更彻底地解释一下这个正则表达式?
  • @MrinalKamboj 正则表达式不是必需的,因为模式匹配不是必需的。一个简单的IndexOf 就足够了,而且它更快更简单。问题在于使用正确的工具来完成这项工作,在这种情况下,使用正则表达式就像在图钉上使用大锤。
【解决方案2】:

在您绝对必须进行字符串搜索的极少数情况下,您可以执行以下操作:

string[] separators = new string[] { "-", ".", "/" };

void DetectCurrentSeparator(string dbDateFormat)
{
    for (int i = 0; i < separators.Length; i++)
    {
        if (dbDateFormat.IndexOf(separators[i]) >= 0)
        {
            // Assuming the above array corresponds with the order of the divider combobox
            combobox_DateFormatDivider.SelectedIndex = i;
            break;
        }
    }
}

现在已经说过了,这个方法应该只需要在程序的生命周期内使用一次 - 当日期格式第一次从数据库中检索时。在剩下的时间里,根本没有理由为此使用任何字符串搜索。您已经从组合框中获得了所需的分隔符,因此不要试图找出现有的分隔符是什么,而是使用一个常见的临时字符并替换它。

像这样初始化:

DateTime now = DateTime.Now;
_dateFormatsMasterList = new List<string>()
{
    "d@M@yy (" + now.ToString("d@M@yy") + ")",
    "dd@M@yy (" + now.ToString("dd@M@yy") + ")",
    "d@MM@yy (" + now.ToString("d@MM@yy") + ")",
    "dd@MM@yy (" + now.ToString("dd@MM@yy") + ")",
    "d@M@yyyy (" + now.ToString("d@M@yyyy") + ")",
    "dd@M@yyyy (" + now.ToString("dd@M@yyyy") + ")",
    "d@MM@yyyy (" + now.ToString("d@MM@yyyy") + ")",
    "dd@MM@yyyy (" + now.ToString("dd@MM@yyyy") + ")",
    "yy@M@d (" + now.ToString("yy@M@d") + ")",
    "yy@M@dd (" + now.ToString("yy@M@dd") + ")",
    "yy@MM@d (" + now.ToString("yy@MM@d") + ")",
    "yy@MM@dd (" + now.ToString("yy@MM@dd") + ")",
    "yyyy@M@d (" + now.ToString("yyyy@M@d") + ")",
    "yyyy@M@dd (" + now.ToString("yyyy@M@dd") + ")",
    "yyyy@MM@d (" + now.ToString("yyyy@MM@d") + ")",
    "yyyy@MM@dd (" + now.ToString("yyyy@MM@dd") + ")"
};

_dateFormatsList = new List<string>(_dateFormatsMasterList);
comboBox_DateFormat.DataSource = _dateFormatsList;

你的 SelectionChanged 事件是这样的:

private void comboBox_DateFormatDivider_SelectedIndexChanged(object sender, EventArgs e)
{
    for (int i = 0; i < _dateFormatsList.Count; i++)
    {
        _dateFormatsList[i] = _dateFormatsMasterList[i].Replace("@", comboBox_DateFormatDivider.SelectedText);
    }
}

【讨论】:

  • 正如问题本身的 cmets 中所述:这需要我将分隔符保存到 db 中,我说过我不想这样做。为什么需要这样做?因为要使用comboBox_DateFormatDivider.SelectedText我必须首先将其设置为用户之前已经选择并保存的值;如果我不进行字符串搜索或不将它保存到数据库,我如何获得这个值?更何况,如果我使用@,那么我什至无法进行字符串搜索(这将毫无意义)
  • 所选的分隔符是您正在保存到数据库的日期格式。当您来显示用户保存的内容之前,您可以从保存的格式中提取分隔符(使用字符串搜索)
  • @user6807975 老兄,当你把一个格式保存到数据库时,它的格式是“dd-mm-yyyy”、“dd.mm.yyyy”或“dd/mm/yy” “ 正确的?分隔符在保存的字符串中就在那里。如果您绝对必须,您可以从该字符串中拉出分隔符,但这只需要做一次 - 当该字符串从数据库中拉出时。在正常程序使用过程中,绝对没有理由使用字符串搜索来进行操作。
  • 然后我需要对那个分隔符进行字符串搜索。我该怎么做? - 这就是这个话题中的问题。而且由于无论如何我都必须搜索字符串,为什么不直接使用@MrinalKamboj 答案,因为它已经在一个地方有了这个和其他所有东西?您的答案仍然需要每个人在有人想要使用此日期格式的每个代码 sn-p 中执行该过程(提取分隔符)。如果我没有@s,使用这种日期格式的人只需从 db 获取它,而无需关心其他任何事情。
  • @Abion47 当然,我同意,用多个字符串搜索做多余的工作是没有意义的,但它仍然必须完成,这就是这里的问题,你的答案并没有回答这个问题。
【解决方案3】:

首先,我想听从 Abion47 的建议,使用变量来存储日期并在列表中使用它。

然后你就可以这样做了

char x = _dateFormatsList[0][1];
        for (int i = 0; i < _dateFormatsList.Count; i++)
            {
                _dateFormatsList[i] = _dateFormatsList[i].Replace(x, comboBox_DateFormatDivider.SelectedItem.ToString()[0]);
            }

【讨论】:

  • 是的。它是一个字符串列表,并且 Replace() 与 char 一起使用,所以直接从列表中获取它。
  • 如果组合框的数据源已排序,则此解决方案将失败,因为 x 的值将是字符“d”。最好使用 Abion47 解决方案中的 DetectCurrentSeparator 方法。
猜你喜欢
  • 2020-02-26
  • 1970-01-01
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 2015-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多