简体   繁体   English

比较两个字符串中的字符

[英]compare the characters in two strings

In C#, how do I compare the characters in two strings. 在C#中,如何比较两个字符串中的字符。
For example, let's say I have these two strings 例如,假设我有这两个字符串
"bc3231dsc" and "bc3462dsc" “ bc3231dsc”和“ bc3462dsc”

How do I programically figure out the the strings 如何以编程方式找出字符串
both start with "bc3" and end with "dsc"? 都以“ bc3”开头并以“ dsc”结尾?

So the given would be two variables: 因此,给定的将是两个变量:

var1 = "bc3231dsc";  
var2 = "bc3462dsc";  

After comparing each characters from var1 to var2, I would want the output to be: 比较从var1到var2的每个字符后,我希望输出为:

leftMatch = "bc3";  
center1 = "231";  
center2 = "462";  
rightMatch = "dsc";  

Conditions: 条件:
1. The strings will always be a length of 9 character. 1.字符串的长度始终为9个字符。
2. The strings are not case sensitive. 2.字符串不区分大小写。

字符串类可以使用2种方法(StartsWith和Endwith)。

After reading your question and the already given answers i think there are some constraints are missing, which are maybe obvious to you, but not to the community. 在阅读了您的问题和已经给出的答案之后,我认为缺少一些约束,这些约束可能对您来说很明显,但对社区而言却不是。 But maybe we can do a little guess work: 但是也许我们可以做一些猜测工作:

  1. You'll have a bunch of string pairs that should be compared. 您将有一堆应该比较的字符串对。
  2. The two strings in each pair are of the same length or you are only interested by comparing the characters read simultaneously from left to right. 每对中的两个字符串长度相同,或者您只对比较从左到右同时读取的字符感兴趣。
  3. Get some kind of enumeration that tells me where each block starts and how long it is. 得到某种枚举,它告诉我每个块从哪里开始以及它有多长时间。

Due to the fact, that a string is only a enumeration of chars you could use LINQ here to get an idea of the matching characters like this: 由于事实,字符串只是char的枚举,您可以在此处使用LINQ来了解匹配字符,如下所示:

private IEnumerable<bool> CommonChars(string first, string second)
{
    if (first == null)
        throw new ArgumentNullException("first");

    if (second == null)
        throw new ArgumentNullException("second");

    var charsToCompare = first.Zip(second, (LeftChar, RightChar) => new { LeftChar, RightChar });
    var matchingChars = charsToCompare.Select(pair => pair.LeftChar == pair.RightChar);

    return matchingChars;
}

With this we can proceed and now find out how long each block of consecutive true and false flags are with this method: 有了这个,我们可以继续进行,现在找出使用此方法的每个连续的true和false标志块有多长时间:

private IEnumerable<Tuple<int, int>> Pack(IEnumerable<bool> source)
{
    if (source == null)
        throw new ArgumentNullException("source");

    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            yield break;
        }

        bool current = iterator.Current;
        int index = 0;
        int length = 1;

        while (iterator.MoveNext())
        {
            if(current != iterator.Current)
            {
                yield return Tuple.Create(index, length);
                index += length;
                length = 0;
            }

            current = iterator.Current;
            length++;
        }

        yield return Tuple.Create(index, length);
    }
}

Currently i don't know if there is an already existing LINQ function that provides the same functionality. 目前,我不知道是否已经存在提供相同功能的LINQ功能。 As far as i have already read it should be possible with SelectMany() (cause in theory you can accomplish any LINQ task with this method), but as an adhoc implementation the above was easier (for me). 据我所读, SelectMany()应该是可能的SelectMany()理论上,您可以使用此方法完成任何LINQ任务),但是作为一个即席实现,以上操作(对我来说)更容易。

These functions could then be used in a way something like this: 然后可以按以下方式使用这些功能:

var firstString = "bc3231dsc";
var secondString = "bc3462dsc";

var commonChars = CommonChars(firstString, secondString);
var packs = Pack(commonChars);

foreach (var item in packs)
{
    Console.WriteLine("Left side:  " + firstString.Substring(item.Item1, item.Item2));
    Console.WriteLine("Right side: " + secondString.Substring(item.Item1, item.Item2));
    Console.WriteLine();
}

Which would you then give this output: 然后您将向哪个输出:

Left side: bc3 Right side: bc3 左侧:bc3右侧:bc3

Left side: 231 Right side: 462 左侧:231右侧:462

Left side: dsc Right side: dsc 左侧:dsc右侧:dsc

The biggest drawback is in someway the usage of Tuple cause it leads to the ugly property names Item1 and Item2 which are far away from being instantly readable. 最大的缺点是在某种程度上使用了Tuple因为它导致了丑陋的属性名称Item1Item2 ,而这些属性名称远不能立即读取。 But if it is really wanted you could introduce your own simple class holding two integers and has some rock-solid property names. 但是,如果真的需要,可以引入一个拥有两个整数的简单类,并具有一些坚如磐石的属性名称。 Also currently the information is lost about if each block is shared by both strings or if they are different. 同样,当前丢失了有关两个块是否共享每个块或它们是否不同的信息。 But once again it should be fairly simply to get this information also into the tuple or your own class. 但是,再次将这些信息也带入元组或您自己的班级应该相当简单。

    static void Main(string[] args)
    {
        string test1 = "bc3231dsc";
        string tes2 = "bc3462dsc";
        string firstmatch = GetMatch(test1, tes2, false);
        string lasttmatch = GetMatch(test1, tes2, true);
        string center1 = test1.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;
        string center2 = test2.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;

    }

    public static string GetMatch(string fist, string second, bool isReverse)
    {
        if (isReverse)
        {
            fist = ReverseString(fist);
            second = ReverseString(second);
        }
        StringBuilder builder = new StringBuilder();
        char[] ar1 = fist.ToArray();
        for (int i = 0; i < ar1.Length; i++)
        {
            if (fist.Length > i + 1 && ar1[i].Equals(second[i]))
            {
                builder.Append(ar1[i]);
            }
            else
            {
                break;
            }
        }
        if (isReverse)
        {
            return ReverseString(builder.ToString());
        }
        return builder.ToString();
    }

    public static string ReverseString(string s)
    {
        char[] arr = s.ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }

Pseudo code of what you need.. 您需要的伪代码..

int stringpos = 0
string resultstart = ""
while not end of string (either of the two)
{
if string1.substr(stringpos) == string1.substr(stringpos) 
resultstart =resultstart + string1.substr(stringpos)
else
exit while
}

resultstart has you start string.. you can do the same going backwards... resultstart有您开始的字符串..您可以执行相同的倒退...

Another solution you can use is Regular Expressions. 您可以使用的另一个解决方案是正则表达式。

Regex re = new Regex("^bc3.*?dsc$");
String first = "bc3231dsc";
if(re.IsMatch(first)) {
    //Act accordingly...
}

This gives you more flexibility when matching. 匹配时可以为您提供更大的灵活性。 The pattern above matches any string that starts in bc3 and ends in dsc with anything between except a linefeed. 上面的模式匹配以bc3开始并以dsc结尾的任何字符串,除了换行符外,其他任何字符串之间都应匹配。 By changing .*? 通过更改。*? to \\d, you could specify that you only want digits between the two fields. 到\\ d,可以指定两个字段之间只希望数字。 From there, the possibilities are endless. 从那里开始,无限的可能性。

using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;

class Sample {
    static public void Main(){
        string s1 = "bc3231dsc";
        string s2 = "bc3462dsc";
        List<string> common_str = commonStrings(s1,s2);
        foreach ( var s in common_str)
            Console.WriteLine(s);
    }
    static public List<string> commonStrings(string s1, string s2){
        int len = s1.Length;
        char [] match_chars = new char[len];
        for(var i = 0; i < len ; ++i)
            match_chars[i] = (Char.ToLower(s1[i])==Char.ToLower(s2[i]))? '#' : '_';
        string pat = new String(match_chars);
        Regex regex = new Regex("(#+)", RegexOptions.Compiled);
        List<string> result = new List<string>();
        foreach (Match match in regex.Matches(pat))
            result.Add(s1.Substring(match.Index, match.Length));
        return result;
    }
}

for UPDATE CONDITION 更新条件

using System;

class Sample {
    static public void Main(){
        string s1 = "bc3231dsc";
        string s2 = "bc3462dsc";
        int len = 9;//s1.Length;//cond.1)
        int l_pos = 0;
        int r_pos = len;
        for(int i=0;i<len && Char.ToLower(s1[i])==Char.ToLower(s2[i]);++i){
            ++l_pos;
        }
        for(int i=len-1;i>0 && Char.ToLower(s1[i])==Char.ToLower(s2[i]);--i){
            --r_pos;
        }
        string leftMatch = s1.Substring(0,l_pos);
        string center1 = s1.Substring(l_pos, r_pos - l_pos);
        string center2 = s2.Substring(l_pos, r_pos - l_pos);
        string rightMatch = s1.Substring(r_pos);
        Console.Write(
        "leftMatch = \"{0}\"\n" +
        "center1 = \"{1}\"\n" +
        "center2 = \"{2}\"\n" +
        "rightMatch = \"{3}\"\n",leftMatch, center1, center2, rightMatch);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM