Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C#: Tekstinkäsittely apua

Sivun loppuun

Rintsi [12.12.2019 21:14:42]

#

Teen C# harjoituksena kopiota Microsoftin laskimesta ja nyt tuntuu että kaipaan apua parissakin asiassa.

Microsoftin laskin lisää välin joka kolmannen merkin väliin, sen toteuttamisessa on ollut vaikeuksia.

Lisäksi Microsoftin laskin pienentää fonttia kun merkkejä on x määrä. Siinä onnistuinkin mutta haluaisin tietää jos sen voisi tehdä jotenkin fiksummin

Alla yllämainitut;

private void textBox1_TextChanged(object sender, EventArgs e)
{
    if(textBox1.Text.Length <= 10)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 33F, System.Drawing.FontStyle.Bold);
    }
    else if(textBox1.Text.Length == 11)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 30F, System.Drawing.FontStyle.Bold);
    }
    else if (textBox1.Text.Length == 12)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 27F, System.Drawing.FontStyle.Bold);
    }
    else if (textBox1.Text.Length == 13)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 24F, System.Drawing.FontStyle.Bold);
    }
    else if (textBox1.Text.Length == 14)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 22F, System.Drawing.FontStyle.Bold);
    }
    else if (textBox1.Text.Length == 15)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 20F, System.Drawing.FontStyle.Bold);
    }
    else if (textBox1.Text.Length == 16)
    {
        textBox1.Font = new Font("Segoe UI Semibold", 19F, System.Drawing.FontStyle.Bold);
    }

    /*
    for (int i = 4; i <= textBox1.Text.Length; i += 4)
    {
        textBox1.Text = textBox1.Text.Insert(i, " ");
        i++;
    }
    */
    /*
    if (textBox1.Text.Length % 3 == 0)
    {
        textBox1.Text = System.Text.RegularExpressions.Regex.Replace(textBox1.Text, ".{3}", "$0 ");
    }
    */
    /*
    var s = textBox1.Text;
    var list = Enumerable
        .Range(0, s.Length / 4)
        .Select(i => s.Substring(i * 4, 4))
        .ToList();
    var res = string.Join(" ", list);
    textBox1.Text = res;
    */

    //textBox1.Text = textBox1.Text.Insert(3, " ");

}

-Rintsi

AtskaFin [12.12.2019 22:23:43]

#

Välien lisäämisen voit toteuttaa seuraavalla tavalla:

string num = "31415926";

for(int i = num.Length - 3; i >= 0; i -= 3)
    num = num.Insert(i, " ");

num = num.Trim();
Console.WriteLine(num);
// --> 31 415 926

Tai tapauksessasi:

for (int i = textBox1.Text.Length - 3; i >= 0; i -= 3)
    textBox1.Text = textBox1.Text.Insert(i, " ");

textBox1.Text = textBox1.Text.Trim();

Fontin koon vaihtelun voisi puolestaan toteuttaa seuraavalla tavalla:

int size;
switch(textBox1.Text.Length) {
    case 16: size = 19; break;
    case 15: size = 20; break;
    case 14: size = 22; break;
    case 13: size = 24; break;
    case 12: size = 27; break;
    case 11: size = 30; break;
    default: size = 33; break;
}

textBox1.Font = new Font("Segoe UI Semibold", size, System.Drawing.FontStyle.Bold);

Rintsi [13.12.2019 04:03:24]

#

Kiitos Fontin koon vaihtelu toimii kuten tarkoituskin mutta tuo väilien lisääminen sai aikaan virheen System.StackOverflowException.

The Alchemist [13.12.2019 04:03:43]

#

AtskaFin kirjoitti:

Välien lisäämisen voit toteuttaa seuraavalla tavalla:

string num = "31415926";

for(int i = num.Length - 3; i >= 0; i -= 3)
    num = num.Insert(i, " ");

num = num.Trim();
Console.WriteLine(num);
// --> 31 415 926

Ei, ei, ei. Numberoiden muotoiluun tulee käyttää asianmukaisia työkaluja. Silmukan jatkamisehdon pitäisi sitä paitsi olla "i > 0" tai "i >= 1". Trim():n kutsuminen on turhaa.

Tällä päässee alkuun:
https://stackoverflow.com/questions/17527847/how-would-i-separate-thousands-with-space-in-c-sharp

Ja arvojen mäppäämiseen x -> y ei kannata käyttää switch-rakennetta vaan Dictionary-luokkaa.

https://www.dotnetperls.com/map

Veikkaan kylläkin, että Windowsin / C#:n GUI-toiminnoissa on jokin widgetti tms. joka osaa skaalata tekstin automaattisesti widgetin leveyden ja sisällön määrän mukaan... Tai ainakin skaalauksen voi tehdä juuri näiden mittojen perusteella sen sijaan, että käsin arpoo sopivia numeroita.

https://stackoverflow.com/questions/9527721/resize-text-size-of-a-label-when-the-text-gets-longer-than-the-label-size

jalski [13.12.2019 21:41:20]

#

The Alchemist kirjoitti:

Ei, ei, ei. Numberoiden muotoiluun tulee käyttää asianmukaisia työkaluja.

Eipä tuo nyt kauhea synti ole, jos tuon muotoilun haluaa tehdä itse. Eli muunnat luvun merkkijonoksi, splittaat ja join metodilla yhdistät merkkijonoksi välilyöntien kanssa.

Merkkijonon splittaamiseen on monta tapaa. Jos split metodi tukee suoraan splittaamista sopiviin ryhmiin niinkuin 8th:lla, niin tätä voi käyttää suoraan. Jos C#:llä on toteutettu pack/unpack, niin tällä onnistuu myös helposti. Säännöllisen lausekkeen avulla onnistuu myös (joku viisaampi voi kertoa onnistuuko ilman merkkijonon kääntämistä).

Alla esimerkkitoteutukset 8th:lla:

: muotoile1  \ n -- s
  >s s:len 3 n:mod 3 2 a:close s:/ " " a:join ;

: muotoile2  \ n -- s
  >s s:len dup >r 3 n:mod dup 0 n:= if
    drop
    ""
  else
    "1:%db" s:strfmt
  then
  r> 3 n:/ n:int "%d:3b" s:strfmt s:+ unpack drop
  " " a:join ;

: muotoile3  \ n -- s
  >s s:rev
  /.{1,3}/ r:+/ " " a:join
  s:rev ;


: app:main
  1234567890 muotoile1 . cr
  1234567890 muotoile2 . cr
  1234567890 muotoile3 . cr
  bye ;

Tulostus:

1 234 567 890
1 234 567 890
1 234 567 890

The Alchemist [14.12.2019 06:02:36]

#

Juu, tämähän oli tosiaan C#-ketju eikä kaatopaikka.

Grez [14.12.2019 11:53:35]

#

jalski kirjoitti:

Eipä tuo nyt kauhea synti ole, jos tuon muotoilun haluaa tehdä itse.

Paskan koodin kirjoittaminen ei tosiaan ole syntiä* - vaikkakin itse paheksun tiettyjä syntejä huonon koodin kirjoittamista vähemmän.

* en ole syntien asiantuntija, joten saa oikaista jos olen väärässä. Olettaisin että se riippuu syystä. Jos kyseessä on laiskuus niin on syntiä, jos osaamattomuus niin ei?

jalski [14.12.2019 12:40:38]

#

Grez kirjoitti:

Paskan koodin kirjoittaminen ei tosiaan ole syntiä* - vaikkakin itse paheksun tiettyjä syntejä huonon koodin kirjoittamista vähemmän.

Ei kai itse tehty toteutus automaattisesti tee koodista paskaa? Aina joskus saattaa tulla vastaan eksoottinen tapaus ettei joku muotoilu olekaan valmiiksi tuettuna, mitä sitten? Pitääkö jättää kokonaan toteuttamatta, ettei vaan tulisi kirjoitettua huonoa koodia? Mikä muuten tekee kyseisestä merkkijonon muotoilun toteuttavasta koodista paskan?

Nämä automaattiset kulttuurin mukaiset muotoilut on ihan kivoja, mutta saattavat aiheuttaa myös tahattomia virheitä. Itse aikoinaan raportoin Component Pascal kääntäjän bugin, missä float tyypin parsiminen heitti poikkeuksen. Toimi hienosti jos kulttuurin mukainen desimaalierotin oli piste, mutta jos olikin pilkku niin ei toiminut enää niin kivasti!

Grez [14.12.2019 13:03:29]

#

jalski kirjoitti:

Ei kai itse tehty toteutus automaattisesti tee koodista paskaa?

Kyllä, ilman hyvää syytä käytettyyn ohjelmistoympäristöön sisältyvän asian toteuttaminen itse tarkoittaa automaattisesti paskaa koodia.

Ihan yhtä lailla kuin copy&paste koodaaminen (eli se että kopioidaan joku toteutus jokaiseen paikkaan missä sitä käytetään ilman että tehdään siitä esim. funktio tai makro) on paskaa koodia.

Se on paskaa koodia, koska se lisää ylläpitotyötä. Tilastollisesti se lisää myös bugien määrää. Lisäksi on todennäköistä että oma toteutus on huonompi kuin koodausympäristöön sisältyvä toteutus (jos näin ei ole ja se tiedetään, niin silloin toki itse tekemiseen voi olla se hyvä syy)

jalski kirjoitti:

Nämä automaattiset kulttuurin mukaiset muotoilut on ihan kivoja

No jos ei tarvita kulttuurinmukaista muotoilua, niin silloin käytetään vakiofunktiota ja sanotaan että ei halua kulttuurinmukaista muotoilua.

jalski kirjoitti:

Itse aikoinaan raportoin Component Pascal kääntäjän bugin, missä float tyypin parsiminen heitti poikkeuksen.

Toki jos tiedetään, että valmisfunktiossa on bugi, niin silloin ollaan taas sen hyvän syyn äärellä. Itselläkin kyllä näitä bugien workaround toteutuksia löytyy, silloin olen yleensä kommentoinut omaan toteutukseen syyn että vakiokirjastossa on bugi ja linkin issueen niin sen oman virityksen voi sitten tulevaisuudessa poistaa kun tulee korjaus.

Se että jokaisen asian koodaisi itse siltä varalta että "ehkä ohjelmointiympäristössä on bugi" on taas sitä paskaa koodausta. Siinä vaiheessa kun ympäristössä alkaa bugeja olla vähän väliä niin suosittelen vaihtamaan työkaluja.

jalski [14.12.2019 19:21:21]

#

The Alchemist kirjoitti:

Ja arvojen mäppäämiseen x -> y ei kannata käyttää switch-rakennetta vaan Dictionary-luokkaa.

Tässä tapauksessa Dictionary luokan käyttö ei kyllä ole perusteltua. Yksinkertainen lookup taulukko tekee tässä tehtävässä asian nopeammin ja yksinkertaisemmin. Lisäksi monissa dictionary toteutuksissa (en tiedä miten C#:n laita on) avain on sisäisesti merkkijono ja ei niin kauhean yllättäen vaatii siten tässä tehtävässä turhan numero - merkkijono muunnoksen.

Grez [16.12.2019 07:23:56]

#

jalski kirjoitti:

Lisäksi monissa dictionary toteutuksissa (en tiedä miten C#:n laita on) avain on sisäisesti merkkijono ja ei niin kauhean yllättäen vaatii siten tässä tehtävässä turhan numero - merkkijono muunnoksen.

C#:ssa ei Dictionaryn avain ole sisäisesti merkkijono (paitsi jos käyttäjä määrittää avaimen tyypiksi merkkijonon). Vaikea ymmärtää miten tähän ketjuun liittyy joidenkin muiden kielien rajoitteet.

Dictionary on tehokkaampi kuin case rakenne jos case-rakenne on kovin pitkä. Tässä tapauksessa ei ole nopeuden kannalta suurta merkitystä kumpaa käyttää.

Itse luultavasti en käyttäisi kumpaakaan vastaavassa tilanteessa, vaan laskisin fontin koon jakolaskulla. Tällä tavoin välttyisi myös turhilta taikanumeroilta. Tosin voihan Dictionaryn tai taulukon muodstaa myös laskemalla ilman taikanumeroita, mutta miksi turhaa.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta