Проблема со сплитом в C # - PullRequest
1 голос
/ 24 июня 2009

Ниже приведен набор данных журнала, найденных в текстовом файле

**********************************************************************************
**2008/04/06** 00:35:35 193111               1008                O          9448050132# 74                               
**2008/04/06** 00:35:35 193116               1009                 O          9448050132# 74                               
 **12/15/2008**   8:36AM 106  01 090788573                             00:01'23" ..06  
**10/10/2008** 14:32:32 4400 4653  00:00:56 26656            0    0           OG AL# 
 &       0000    0000                                      
N 124 00 8630    T001045 **10/16** 05:04 00:01:02 A 34439242360098
***************************************************************************************

Мне нужно извлечь только данные даты (может быть 200/04/06 или 10/16) из всех вышеприведенных строки отобразить его в текстовом поле.

Я знаю, как отделить дату, если данные упорядочены как показано ниже

***************************************************************************************
10/10/2008 14:32:32 4400 4653  00:00:56 26656            0    0           OG AL#

10/10/2008 14:33:29 4400 4653  00:00:02 26656434         0    0           OG LL#

10/10/2008 14:33:31 4400 4653  00:00:11 26656434         0    0           OG LL#
***************************************************************************************

Код для этого:

        StreamReader rr = File.OpenText("C:/1.txt");
        string input = null;
        while ((input = rr.ReadLine()) != null)
        {                
            char[] seps = { ' ' };
            string[] sd = input.Split(seps, StringSplitOptions.RemoveEmptyEntries);

            string[] l = new string[1000];

            for (int i = 0; i < sd.Length; i++)
            {
                l[i] = sd[i];
                textBox4.AppendText(l[i] + "\r\n");

                //The date is 10 characters in length. ex:06/08/2008
                if (l[i].Length == 10)                    
                textBox1.AppendText(l[i]+"\r\n");

                //The time is of 8 characters in length. ex:00:04:09
                if (l[i].Length == 8)
                textBox2.AppendText(l[i] + "\r\n");

                //The phone is of 11 characters in length. ex:9480455302#
                if (l[i].Length == 11)
                textBox3.AppendText(l[i] + "\r\n");                    
            }                
         }

Можетпожалуйста, помогите мне с этим !!!!

Ответы [ 6 ]

4 голосов
/ 24 июня 2009

лучший вариант в этом контексте - использовать регулярные выражения, которые более точны и не требуют какого-либо форматирования ... общее регулярное выражение будет "[0-9] {2} [/] {1} [0-9] {2} [/] {1} [0-9] {4}", вы можете настроить его под свои потребности, в совпадениях вы можете найти значение совпадения, которое является точной датой. я вижу хорошего оценщика регулярных выражений, встроенного в silverlight http://regexhero.net/

2 голосов
/ 24 июня 2009

В вашем коде есть несколько странностей. В частности, следующая строка внутри цикла while:

string[] l = new string[1000];

Это создаст массив строк из 1000 элементов для каждого раунда цикла while. Позже вы будете использовать только элемент i в этом массиве, оставляя 999 других элементов неиспользованными. Судя по остальной части кода, вы можете просто использовать sd[i].

Кроме того, я предполагаю, что textBox1, textBox2 и textBox3 никогда не должны содержать одно и то же значение; если значение входит в один из них, оно никогда не должно переходить в другой из них (кроме textBox4, который, кажется, собирает все данные). Кроме того, нет необходимости продолжать тестировать значение, как только будет найдено правильное текстовое поле.

Наконец, следующая строка внутри цикла while:

char[] seps = { ' ' };

Это создаст идентичный массив символов для каждого раунда в цикле while; Вы можете переместить это за пределы цикла и просто использовать тот же массив.

Что касается определения даты; Исходя из представленных вами данных, дата - это единственные данные, которые содержат символ /, поэтому вы можете проверить это, а не длину.

Вы можете попробовать следующее:

StreamReader rr = File.OpenText("C:/1.txt");
string input = null;
char[] seps = { ' ' };
while ((input = rr.ReadLine()) != null)
{    
    string[] sd = input.Split(seps, StringSplitOptions.RemoveEmptyEntries);
    for (int i = 0; i < sd.Length; i++)
    {
        textBox4.AppendText(sd[i] + "\r\n");

        if (sd[i].Contains("/"))
        {
            // The string contains a / character; assume it is a date
            textBox1.AppendText(sd[i] + "\r\n");
        }
        else if (sd[i].Length == 8)
        {
            //The time is of 8 characters in length. ex:00:04:09
            textBox2.AppendText(sd[i] + "\r\n");
        }
        else if (sd[i].Length == 11)
        {
            //The phone is of 11 characters in length. ex:9480455302#
            textBox3.AppendText(sd[i] + "\r\n");
        }
    }                
 }
2 голосов
/ 24 июня 2009

Я попробовал regex в консольном приложении с текстом, который вы указали. Это работает:

        Regex reg = new Regex(@"\d{4}/\d{2}/\d{2}|\d{2}/\d{2}/\d{4}|\d{2}/\d{2}");

        string str = @"2008/04/06 00:35:35 193111 1008 O 9448050132# 74
           2008/04/06 00:35:35 193116 1009 O 9448050132# 74
           12/15/2008 8:36AM 106 01 090788573 00:01'23' ..06
           10/10/2008 14:32:32 4400 4653 00:00:56 26656 0 0 OG AL# & 0000 0000
           N 124 00 8630 T001045 10/16 05:04 00:01:02 A 34439242360098";

        MatchCollection mc = reg.Matches(str);

        foreach (Match m in mc)
        {
            Console.WriteLine(m.Value);
        }

Я думаю, что вы можете читать строки одну за другой, получать совпадения из каждой строки и сохранять их в некотором списке или массиве для последующего использования.

0 голосов
/ 24 июня 2009

Вы должны использовать регулярные выражения для поиска дат в вашем файле журнала. Правильное регулярное выражение для ваших форматов даты:

@"(\d{2}|\d{4}){1}/\d{2}(/\d{2}|\d{4})*"

как это будет обрабатывать дд / мм / гггг или гггг / мм или дд / мм и т. Д.

Это код C #, который вы можете использовать:

Функция вызова:

private static void RegexGetDates()
{
    string fileText = File.ReadAllText("..\\..\\Data\\RegexSample2.txt");

    List<string> matchesList = MyRegEx.GetMatchedDates(fileText);
    foreach (string s in matchesList)
        Console.WriteLine(s);
}

Функция для получения дат из входной строки:

/// <returns>Returns all dates in logString as List<string><returns>
public static List<string> GetMatchedDates(String logString)
{
    List<string> dateList = new List<string>();
    Regex r;
    // Matches all the data between the quotes inside var matches
    r = new Regex(@"(\d{2}|\d{4}){1}/\d{2}(/\d{2}|\d{4})*", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
    for (Match m = r.Match(logString); m.Success; m = m.NextMatch())
    {
        dateList.Add(m.Value);
    }

    return dateList;
}
0 голосов
/ 24 июня 2009
Regex is the best choice if you consider to an iterative approach

 while ((input = rr.ReadLine()) != null)
{
   foreach(var item in input.Split(' ') )
{
    if(item.Contains("/"))
            textBox4.AppendText( item + "\r\n");

}



  }
0 голосов
/ 24 июня 2009

Похоже, что у дат есть знак «/», вы можете использовать его, чтобы получить индекс, а затем вернуться назад, пока не дойдете до начала строки или пробела, и идти вперед до пробела.

псевдокод:

получить позицию первого / в строке

индекс = позиция

startpos, endpos;

пока индекс! = 0

while char [index]! = ''

index-- // делайте это, пока не окажетесь в начале даты (то есть начало строки пробела перед датой // индекс найден? startpos = index

индекс = позиция в то время как char [index]! = '' index ++ // делать это до тех пор, пока вы не окажетесь в месте после даты

// индекс найден?

endpos = index

date = подстрока (startpos, endpos - startpos)

P.S. Я сосу на RegEx ...

...