Autor Zpráva
__martin
Profil *
Ahoj,

dělám aplikaci v C#. Načítám textový soubor. Celkem 35 000 řádků. V každém řádku 6 - 8 sloupců. Načtu textový soubor do proměnné a zpracovávám pomocí regulárního výrazu. Řekněme, že ve 3. a 4. sloupci je se vyskytuje 23 tísíc krát řetězec "2000 2000". Já toto číslo potřebuji nahradit za 2000 + číslo výskytu. Výsledek by byl tedy: "20000001 20000001", "20000002 20000002"...

Naprogramovat jsem to dokázal (kód níže), problém je, že celé nahrazení trvá 18 minut, což nený zrovna málo. Soubor má 2,5MB a já bych rád zpracoval třeba i soubory větší (40MB).
String result = NACTENY SOUBOR;

// pole cisla obsahuje cisla (cca 40), ktera je nutna nahradit, v nasem pripade 2000, ale i dalsi

for (int x = 0; x < cisla.Count; x++)
{
    String pattern = "(" + cisla[x] + ")(\\s+)(" + cisla[x] + ")";

    Regex reg_replace = new Regex(pattern);
    int pocet = reg_replace.Matches(result).Count; // pocet výskytů konkrétního čísla

    int cislo = 1;
    String replacement = "";
    
    // pokud první číslo (např. 2000) je obsaženo 23 tisíc krát, tak tolikrát se tento cyklus provede
    for (int i = 0; i <= pocet; i++)
    {
        replacement = "${1}" + cislo.ToString("0000") + "${2}${3}" + cislo.ToString("0000");
        result = reg_replace.Replace(result, replacement, 1, i);
        cislo++;
    }
}


Já jsem se chtěl zeptat, jestli není možné se zbavit vloženého cyklu, aby se neprováděl tolikrát. Možná existuje nějaký interní čítač, ze kterého by se dalo jednoduše dostat pořadí konkrétního výskytu. Takže řádek
replacement = "${1}" + cislo.ToString("0000") + "${2}${3}" + cislo.ToString("0000");

by mohl vypadat takto

replacement = "${1}" + INTERNI_KONSTANTA.ToString("0000") + "${2}${3}" + INTERNI_KONSTANTA.ToString("0000");

a ja bych mohl vypustit cyklus. Dá se tomu rozumět? Nějaké další návrhy na zrychlení? Děkuji.
Chamurappi
Profil
Reaguji na __martina:
\\1
__martin
Profil *
Chamurappi:
Díky moc, nevím, jestli jsem to dobře pochopil. Vyplývá z toho, že "INTERNI_KONSTANTA" můžu nahradit za \\1? Tedy že celý cyklus kódem:
replacement = "${1}\\1${2}${3}\\1";
result = reg_replace.Replace(result, replacement);


Jak se \\1 říká? Rád bych si to vygooglil. Protože po spuštění kódu výše se \\1 nahradí jen za \1. Díky
Chamurappi
Profil
Reaguji na __martina:
Aha, pardon, dotaz jsem prohlédl jen zběžně a odpověděl na něco jiného.

Druhým argumentem funkce Regex.Replace může být delegát MatchEvaluator, tedy v podstatě funkce — v ní si můžeš inkrementovat proměnnou a náhradou bude řetězec, který tato funkce vrací. Na příklad použití s anonymním delegátem se mrkni třeba sem.
_es
Profil
__martin:
problém je, že celé nahrazení trvá 18 minut
Asi by sa to veľmi zrýchlilo úplným odstránením regulárnych výrazov a nahradením ich funkčnosti vhodným použitím iných metód pre textové reťazce.
__martin
Profil *
Díky moc! Zrychlení na 15 vteřin!
                    for (int x = 0; x < cisla.Count; x++)
                    {
                        String pattern = "(?<param1>" + cisla[x] + ")(?<param2>\\s+)(?<param3>" + cisla[x] + ")";

                        Regex reg_replace = new Regex(pattern);
                        int pocet = reg_replace.Matches(result).Count;

                        result = reg_replace.Replace(result, this.Regular);
                        citac = 0;
                    }
                    
        public static int citac = 0;

        public string Regular(Match m)
        // Replace each Regex cc match with the number of the occurrence.
        {
            citac++;
            return m.Groups["param1"].Value + citac.ToString("0000") + m.Groups["param2"].Value + m.Groups["param3"].Value + citac.ToString("0000"); 
        }


jsou to dva vytržené kusy kódu, ale snad někomu pro ilustraci pochopí. Díky!

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: