Показаны сообщения с ярлыком perl. Показать все сообщения
Показаны сообщения с ярлыком perl. Показать все сообщения

вторник, 21 июля 2009 г.

Perl, C# и регулярные выражения

Казалось бы, Perl и C# -- языки очень разные, но как оказывается, C# поддерживает стандарт де-факто регулярных выражений – Перл совместимые регулярные выражения.

Конечно же, для Perl регулярные выражения родные, и сними намного удобней работать именно в Перле, но, для того чтобы регулярные выражения заработали в C# -- достаточно просто взять и скопировать их из перлового скрипта.

Единственное что мне пока что не нравиться – это то, что регекспы в C# компилируется в момент выполнения. Таким образом, можно допустить ошибку где-то в тридесятом условии, в тридевятом вызове метода, и тогда вылезет исключение. В Перл регекспы проверяться в момент компиляции скрипта и банальные опечатки вылезают сразу же.

Именно поэтому, я разрабатываю и тестирую регекспы в Перл, и лишь потом переношу их в C#. Это получается быстрей удобней и стабильней.

Напоследок хочу продемонстрировать на простом примере, что уже сейчас код на C# выглядит ненамного избыточней, чем его аналог на Perl.

Следующий код выводит дату и время из строчек массива variants:

#!perl
my @variants =
(
q~^92(28/10/2002)**&[19:10:50]@Comment: Text String"~,
q~^-06/02/2002*$21:55:45~,
q~^*13/08/2002*DX145&[22:50:20]@Comment: Text String~,
);

foreach my $variant ( @variants ) {

if ( $variant =~ m!([0-3][0-9]/[0-1][0-9]/[1-2]\d\d\d).+?
                       ([0-2][0-9]:[0-5][0-9]:[0-5][0-9])!x )
{
print "Date: $1; Time: $2\n";
}
else {
print "Failed to parse string: $variant\n";
}
}


И пример на C#:

using System;
using System.Text.RegularExpressions;

namespace RegexTest
{
class Program
{
static void Main(string[] args)
{
string[] variants = {
@"^92(28/10/2002)**&[19:10:50]@Comment: Text String""",
@"^-06/02/2002*$21:55:45",
@"^*13/08/2002*DX145&[22:50:20]@Comment: Text String",
};
Regex veriantRegex = new Regex(@"(?<date>[0-3][0-9]/[0-1][0-9]/[1-2]\d\d\d).+?" +
@"(?<time>[0-2][0-9]:[0-5][0-9]:[0-5][0-9])" );
foreach (var variant in variants)
{
Match match = Match.Empty;
if ((match = veriantRegex.Match(variant)) != Match.Empty)
{
Console.WriteLine("Date: {0}; Time: {1}", match.Groups["date"].Value,
match.Groups["time"].Value);
}
else
{
Console.WriteLine("Failed to parse string: {0}", variant);
}
}
}
}
}


Output:

Date: 28/10/2002; Time: 19:10:50
Date: 06/02/2002; Time: 21:55:45
Date: 13/08/2002; Time: 22:50:20

вторник, 7 апреля 2009 г.

Экономим байты исходного кода. Реализация алгоритма QSort

Однажды, когда я проходил трейнинг по C#, нам было задано домашние задание, одним из пунктов которого было реализовать алгоритм быстрой сортировки(QSort) на C#. По достаточно хорошему описанию алгоритма на страницах Википедии, я все-таки реализовал алгоритм по-своему, но решил продолжить поиск наиболее «короткого» решении. И я его нашел. Следующий код написан на языке Perl, и это то, к чему нужно стремиться:

sub qsort {
return () if !@_;
return (qsort(grep { $_ < $_[0] } (@_)[1..$#_]), $_[0],
qsort(grep { $_ >= $_[0] } (@_)[1..$#_]));
}


Превосходно! Реализация алгоритма наглядна и прекрасно запоминается. Я попытался переписать исходный код с Perl на C#, и вот что у меня получилось:

public static List<T> QSort<T>(List<T> sourceArray)
where T : IComparable<T>
{
if ( sourceArray.Count == 0 )
{
return new List<T>();
}
T firstItem = sourceArray[0];
sourceArray.RemoveAt(0);

List<T> greaterList = new List<T>();
List<T> lessList = new List<T>();
List<T> sortedArray = new List<T>();


foreach (T item in sourceArray)
{
if (item.CompareTo(firstItem) < 0) lessList.Add(item);
}

foreach (T item in sourceArray)
{
if (item.CompareTo(firstItem) >= 0) greaterList.Add(item);
}

sortedArray.AddRange(QSort(lessList));
sortedArray.Add(firstItem);
sortedArray.AddRange(QSort(greaterList));

return sortedArray;
}


Вроде бы ничего, по крайней мере, задание сдал. Но, вот недавно я увидел следующее решение на C#:

public static IEnumerable<T> QuickSort<T>(this IEnumerable<T> list)
where T : IComparable
{
if (!list.Any())
{
return Enumerable.Empty<T>();
}
var pivot = list.First();
var smaller = list.Where(item => item.CompareTo(pivot) <= 0).QuickSort();
var larger = list.Where(item => item.CompareTo(pivot) > 0).QuickSort();

return smaller.Concat(new[] {pivot}).Concat(larger);
}


Кто короче?! ;)

вторник, 24 марта 2009 г.

Крик души ;)

public static Testplan ParseFile(string filePath)
{
ApplicationClass excel = new ApplicationClass();
excel.Visible = true;
excel.Workbooks.Open(filePath, false, false, null, null, null,
true, null, null, null, null, null, null,
null, null);

// А все таки фигово, что в 3-м Сишарпе нет именованных аргументов
// и аргументов по умолчанию. Ждем-с 4-го Сишарпа :(

return new Testplan(null, null, null);
}


Тоже самое, только на Perl:

my $Book = $Excel->Workbooks->Open( {
FileName => $FILE_NAME,
UpdateLinks => 0,
ReadOnly => 1,
IgnoreReadOnlyRecommended => 1,
}
) or die("Cannot open file $FILE_NAME");


UPD:

На самом деле, пропущенные параметры нужно заполнять при помощи значения Missing.Value, которое описано в System.Reflection. В противном случае (если использовать null), можно нарваться на Exception.



excel.Workbooks.Open(filePath, false, false, Missing.Value, Missing.Value, Missing.Value,
true, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value);
 

.NET ate my MOSK;. Powered By Blogger © 2009 Bombeli | Theme Design: ooruc