В предыдущем посте на эту тему я написал о том, как "кривые" телефоны привести к формату. При этом, если одна строка на входе (в соответствующем поле) содержала список телефонов через запятую, то и на выходе ей соответствовала одна строка со списком телефонов в поле, так же через запятую. Исправлялся только формат.

Разберем более сложный случай - из каждой строки на входе нужно получить на выходе столько строк, сколько там есть телефонов. Например, на входе строка со значением в поле "8 963 1112233, 556 5554; 667 67 67", на выходе должна дать три строки: "+7(963)111-22-33", "+7(495)556-55-54" и "+7(495)667-67-67". Разделитель может быть как запятая, так и точка с запятой.

Для этого вставляем в поток Script Component, где создаем Output для которого свойство SyncronousInputID выставляем в None:

Код пишем по такому образцу:

...
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
...
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        if (!Row.PhonesIn_IsNull)
        {
            if (!Row.PhonesIn_IsNull)
            {
                var countryPref = "7";      // we assume, that all phones are domestic and harcode country code
                var defaultCityPref = "495";      // default city or operator prefix
                var phones = Row.PhonesIn.Replace(';', ',').Split(',');   // phones in string should be separated with commas or semicolons
                var e = phones.GetEnumerator();
                while (e.MoveNext())
                {
                    var phone = e.Current.ToString().Trim();
                    var r1 = new Regex(@"(.*)(\d).*(\d).*(\d).*(\d).*(\d).*(\d).*(\d)\D*$", RegexOptions.IgnoreCase);  // expression to match phone number
                    var r2 = new Regex(@".*(\d{3})\D*$", RegexOptions.IgnoreCase); // expression to match city or operator prefix
                    var m = r1.Match(phone);
                    if (m.Success)
                    {
                        var pref = r2.Match(m.Groups[1].Value).Groups[1].ToString();    // get prefix out
                        pref = (pref.Equals("095")) ? "495" : pref;         // replace old Moscow prefix with new
                        if (pref.Length == 0) pref = defaultCityPref;
                        Output0Buffer.AddRow();
                        Output0Buffer.Phone=
                            (
                            "+" + countryPref +         // phones prefixed with '+' and country code
                            "(" + pref + ")" +          // city or operator prefix taken in curves
                            m.Groups[2].Value +
                            m.Groups[3].Value +
                            m.Groups[4].Value + "-" +
                            m.Groups[5].Value +
                            m.Groups[6].Value + "-" +
                            m.Groups[7].Value +
                            m.Groups[8].Value);
                    }
                }
            }
        }
    }

Для более подробной информации можно почитать "Creating an Asynchronous Transformation with the Script Component". О чем ещё следует упомянуть - асинхронные компоненты "вбирают" все данные потока перед тем как их выпустить (а не порциями) - это может быть важно, если у вас много данных.