Podmínky

Pro posun na další strany použijte kurzorové šipky

Ⓒ Tomáš Bořil
borilt@gmail.com, 24. 3. 2020

Větvení programu na základě podmínek

Často chceme některé bloky příkazů provádět pouze, pokud je splněna nějaká podmínka.

Například: urči průměrnou hodnotu F1 pouze, pokud je segment vokálem.

Nebo: pokud vokál trvá méně než 100 ms, urči jednu průměrnou hodnotu F0, v opačném případě urči dvě hodnoty F0 (na začátku a na konci).

Kontrola předpokladů: pokud se 1. vrstva TextGrid nejmenuje 'slova', napiš chybovou hlášku informující o problému a ukonči předčasně skript.

Podmínky mohou obsahovat operátory = (je rovno), <> (není rovno), < (menší), <= (menší nebo rovno), >, >=.

Složené podmínky vytváříme operátory and (a zároveň), or (nebo), případně not pro negaci: not (cislo = 2) čteme „neplatí, že cislo je 2“.

Např. vokál [a] kratší než 100 ms: lab$ = "a" and trvani < 0.1

Hledání více variant

Např. dotaz, zda je lab$ vokál, můžeme řešit podmínkou

lab$ = "a" or lab$ = "a:" or lab$ = "e" or lab$ = "e:" atd...

Je to naprosto v pořádku, jen to vede na zdlouhavý zápis.

Funkce index()

Můžeme také narazit na použití funkce index, kterou však důrazně nedoporučuji, jelikož může vést k nepříjemným omylům.

index("kde", "co"), zjišťuje, zda řetězec "co" je obsažen v řetězci "kde".

vokaly$ = "i:e:a:o:u:"
naše podmínka: (lab$ <> "") and (index(vokaly$, lab$))

Součástí dotazu je, zda label není prázdný. Prázdný řetězec je totiž vždy součástí jakéhokoliv řetězce, takže by v takovém případě index() vracel vždy nález.

Pokud si někdo myslí, že tento skript bude hledat pouze dlouhé vokály, je na omylu. Podmínku splňují i krátké i e a o u, víte proč?

Přemýšlejte, asi na to přijdete. Odpověď je na následující straně.

Funkce index()

Protože samotné „krátké“ znaky (např. e) jsou také součástí našeho řetězce. Dvojtečka za nimi v tu chvíli nevadí, protože tu nehledáme.

Záleží na použité transkripci. Někdo bude potřebovat jiný výčet, např. v následujícím příkladě je samozřejmě nutné uvést znaky pro krátké i dlouhé vokály.

vokaly$ = "uieaoíéáúó"

Pokud by někdo ale napsal následující, nesmí se divit, že mu to bude hledat např. i diftong "ou", který je též součástí řetězce...

vokaly$ = "aeiouáéíóú"

Hledání více variant: nejlepší řešení

Jak vidíme, mnohem bezpečnější je psát staré dobré

lab$ = "a" or lab$ = "a:" or lab$ = "e" or lab$ = "e:" atd...

Je to sice delší zápis, ale s použitím schránky ctrl+c a ctrl+v ho vytvoříme rychle.

Toto byly zatím jen samostatné podmínky (matematický výraz). Jak podle nich řídit běh programu, se dozvíte na další straně.

Jednoduchá podmínka if – endif

Pokud je podmínka za příkazem if splněna, provádění skriptu pokračuje řádky uvnitř.

Pokud splněna není, program rovnou přeskočí na další řádek za endif.

Estetická poznámka: vnitřní části odsazujte mezerami nebo tabulátorem.

Tipněte si, co bude výstupem následujícího skriptu.

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Jednoduchá podmínka if – endif

clearinfo                                          <==
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080                                     <==

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100                                  <==
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Podmínka trvani < 0.100 platí, takže vstoupíme dovnitř bloku if.

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.                   <==
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.              <==
endif

printline Hotovo.

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif                                              <==

printline Hotovo.

Konec příkazu if, pokračujeme následujícími řádky.

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.                                  <==

trvani: 0.08

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.080

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

trvani: 0.08

Jednoduchá podmínka if – endif

Tipněte si, jak dopadne skript s touto hodnotou trvani.

clearinfo
trvani = 0.13

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Jednoduchá podmínka if – endif

clearinfo                                          <==
trvani = 0.13

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.13                                      <==

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

trvani: 0.13

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.13

if trvani < 0.100                                  <==
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

Podmínka trvani < 0.100 neplatí, takže skočíme na nejbližší řádek endif.

trvani: 0.13

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.13

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif                                              <==

printline Hotovo.

Konec příkazu if, pokračujeme následujícími řádky.

trvani: 0.13

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.13

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.                                  <==

trvani: 0.13

Jednoduchá podmínka if – endif

clearinfo
trvani = 0.13

if trvani < 0.100
    printline Kratší než 100 ms.
    printline Stačí jedna hodnota F0.
endif

printline Hotovo.

trvani: 0.13

Podmínka if – else – endif

Příkaz if je možno volitelně doplnit o sekci else, jejíž vnitřek se provede pouze v případě, že výše uvedená podmínka u if není splněna.

clearinfo
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Podmínka if – else – endif

clearinfo                                          <==
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Podmínka if – else – endif

clearinfo
trvani = 0.08                                      <==

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

trvani: 0.08

Podmínka if – else – endif

clearinfo
trvani = 0.08

if trvani < 0.100                                  <==
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Podmínka platí.

trvani: 0.08

Podmínka if – else – endif

clearinfo
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.                   <==
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Poslední příkaz v rámci této podmínky, skočíme na endif.

trvani: 0.08

Podmínka if – else – endif

clearinfo
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif                                              <==

printline Hotovo.

Konec příkazu if – else – endif, dále program pokračuje normálně následujícími řádky.

trvani: 0.08

Podmínka if – else – endif

clearinfo
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.                                  <==

trvani: 0.08

Podmínka if – else – endif

clearinfo
trvani = 0.08

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

trvani: 0.08

Podmínka if – else – endif

clearinfo                                          <==
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Skript pro jinou hodnotu trvani.

Podmínka if – else – endif

clearinfo
trvani = 0.15                                      <==

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100                                  <==
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Podmínka neplatí, skáčeme na další sekci if – else – endif.

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else                                               <==
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

Vstoupíme do sekce, která se provádí, když výše uvedená podmínka neplatí.

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.               <==
endif

printline Hotovo.

Poslední příkaz v rámci této sekce, skočíme na endif.

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif                                              <==

printline Hotovo.

Konec příkazu if – else – endif, dále program pokračuje normálně následujícími řádky.

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.                                  <==

trvani: 0.15

Podmínka if – else – endif

clearinfo
trvani = 0.15

if trvani < 0.100
    printline Kratší než 100 ms.
else
    printline Trvá minimálně 100 ms.
endif

printline Hotovo.

trvani: 0.15

Otázka

Jak dopadne výstup následujícího skriptu?

cislo = 4

if cislo < 5
    printline Číslo je menší než 5.
    cislo = cislo + 1
else
    printline Číslo není menší než 5.
endif

printline Hotovo.
cislo = 4

if cislo < 5
    printline Číslo je menší než 5.
    cislo = cislo + 1
else
    printline Číslo není menší než 5.
endif

printline Hotovo.

Protože podmínka if je splněna, vypíše se řádek "Číslo je menší než 5."

Proměnná cislo se zvýší o jedničku a skript pokračuje příkazy za endif.

Přestože je nyní cislo rovno 5, testování podmínky se neopakuje. Větvení if není cyklus!

Skript končí napsáním řádku "Hotovo."

cislo: 4 5

Podmínka if – elsif – else – endif

Příkaz if je možno volitelně doplňovat o další konkrétní podmínky v sekcích elsif. Sekce else je opět nepovinná.

Jakmile je nalezena první podmínka, která platí, provedou se příslušné vnitřní příkazy a blok if – endif je ukončen, i kdyby platily některé následující varianty podmínek elsif.

Poznámka: nejedná se o překlep, příkaz se skutečně zapisuje elsif.

if lab$ = "a" or lab$ = "a:"
    printline Je to krátký nebo dlouhý vokál [a].
elsif lab$ = "e" or lab$ = "e:"
    printline Je to krátký nebo dlouhý vokál [e].
else
    printline Je to něco jiného.
endif

Otázka 1

clearinfo

cislo = 3

if cislo < 5
    printline Menší než 5.
elsif cislo < 10
    printline Menší než 10.
endif

printline Hotovo.

Jaké řádky vypíše skript pro cislo = 3?

  1. Menší než 5. Menší než 10. Hotovo.
  2. Menší než 5. Hotovo.
  3. Menší než 5.
  4. Menší než 10. Hotovo.
  5. Menší než 10.
  6. Hotovo.

Nalezne se první podmínka, která je splněna, pak program skočí za endif.

Je splněna podmínka cislo < 5, skript pak pokračuje následujícími řádky za příslušným endif.

Vůbec není důležité, že by platila i druhá podmínka cislo < 10.

Otázka 2

clearinfo

cislo = 5

if cislo < 5
    printline Menší než 5.
elsif cislo < 10
    printline Menší než 10.
endif

printline Hotovo.

Jaké řádky vypíše skript pro cislo = 5?

  1. Menší než 5. Menší než 10. Hotovo.
  2. Menší než 5. Hotovo.
  3. Menší než 5.
  4. Menší než 10. Hotovo.
  5. Menší než 10.
  6. Hotovo.

Nalezne se první podmínka, která je splněna, pak program skočí za endif.

První podmínka cislo < 5 není splněna, proto se začne zkoumat další podmínka.

Podmínka cislo < 10 platí, skript pak pokračuje následujícími řádky za příslušným endif.

Otázka 3

clearinfo

cislo = 15

if cislo < 5
    printline Menší než 5.
elsif cislo < 10
    printline Menší než 10.
endif

printline Hotovo.

Jaké řádky vypíše skript pro cislo = 15?

  1. Menší než 5. Menší než 10. Hotovo.
  2. Menší než 5. Hotovo.
  3. Menší než 5.
  4. Menší než 10. Hotovo.
  5. Menší než 10.
  6. Hotovo.

Nalezne se první podmínka, která je splněna, pak program skočí za endif.

První podmínka cislo < 5 není splněna, proto se začne zkoumat další podmínka.

Podmínka cislo < 10 také neplatí.

Vzhledem k tomu, že již není k dispozici žádná další varianta podmínky ani sekce else, skript pokračuje následujícími řádky za příslušným endif.

Úkol 1

Vytvořte skript, který vypíše celá čísla 1 až 20 kromě čísel 5 a 17.

Použijte jeden cyklus a podmínku.

Zkuste úlohu vyřešit sami, na další straně následuje řešení.

Úkol 1: řešení

clearinfo

for i from 1 to 20
    if i <> 5 and i <> 17
        printline 'i'
    endif
endfor

Úkol 2

Vytvořte skript, který projde 2. vrstvu v označeném objektu TextGrid (obsahuje segmenty) a vypočte, kolik intervalů, které nemají prázdný label, trvá méně než 100 ms.

Zkuste si promyslet, jak na to, na následující straně je nápověda.

priklad_data.zip (milanek.TextGrid)

Úkol 2: nápověda

Pomocí for cyklu projdeme postupně všechny intervaly 2. vrstvy.

Zjistíme vždy label daného intervalu.

Pokud to není prázdný řetězec (podmínka if lab$ <> ""), zjistíme počáteční a koncový čas intervalu.

Vypočteme trvání intervalu a podmínkou if se zeptáme, zda je menší než 100 ms.

Pokud ano, chtělo by to navýšit hodnotu nějakého počítadla o jedničku.

Ještě před for cyklem proto zavedeme proměnnou s počáteční hodnotou pocet = 0.

Po skončení for cyklu vypíšeme hodnoty proměnné pocet.

Než začnete tvořit, přečtěte si ještě tipy na následující stránce.

Úkol 2: tipy

Nesnažte se vytvořit celý skript rovnou celý najednou. Nikdo tak nepracuje. Bezpečnější je tvořit skript po částech a být si jistý funkčností jednotlivých kroků.

  • Zjistěte a vypište nejdříve jen počet intervalů.

  • Pokud toto funguje, vytvořte for cyklus, projděte intervaly a vypište jejich labely.

  • Jestliže je vše v pořádku, vyberte podmínkou jen neprázdné labely a opět je nechte vypsat.

  • Nyní vypočtěte a vypisujte trvání těchto vybraných intervalů.

  • Přidejte podmínku a počítadlo.

  • Smažte (zakomentujte) všechny pomocné výpisy.

Zkuste skript sami vytvořit, následuje řešení.

# Spočítá neprázdné intervaly < 100 ms
clearinfo
pocetInt = Get number of intervals: 2
# printline 'pocetInt'
pocet = 0   ; počet neprázdných intervalů < 100 ms
for i from 1 to pocetInt
    lab$ = Get label of interval: 2, i
    if lab$ <> ""
        # printline 'lab$'
        t1 = Get start point: 2, i
        t2 = Get end point: 2, i
        trvani = t2 - t1
        # printline 'trvani'
        if trvani < 0.1
            pocet = pocet + 1
        endif
    endif
endfor

printline Nalezený počet: 'pocet'

Úkol 2: řešení

Všimněte si odsazování vnořených sekcí mezerami. Velice to přispívá k přehlednosti, co k sobě patří, kde je začátek a konec.

Úkol 3

Vytvořte skript, který projde 2. vrstvu v označeném objektu TextGrid (obsahuje segmenty) a vypočte průměrné trvání krátkých vokálů.

Zkuste si promyslet, jak na to, na následující straně je nápověda.

milanek.TextGrid

Úkol 3: nápověda

Projít intervaly TextGridu umíme. Musíme nejdříve zjistit jejich počet, a pak použít for cyklus.

Uvnitř cyklu musíme vždy zjistit konkrétní label. Pro výběr pouze krátkých vokálů můžeme využít podmínku if (lab$ <> "") and (index("uieao", lab$)).

Při splnění podmínky zjistíme začátek a konec intervalu a vypočteme trvání.

Průměr se počítá jako celkový součet lomeno počtem. Bude to tedy chtít ještě před for cyklem zavést proměnné soucet = 0 a pocet = 0 a uvnitř podmínky pocet zvyšovat a k soucet přičítat aktuální trvání.

Na konci cyklu obě hodnoty vydělíme a uložíme do proměnné prumer, kterou následně vypíšeme.

Tip: opět tvořte postupně po funkčních částech a používejte kontrolní printline, abyste měli jistotu, že jednotlivé části dělají opravdu to, co chcete. Další strana obsahuje řešení.

# Zjistí průměrné trvání krátkých vokálů
clearinfo
pocetInt = Get number of intervals: 2

soucet = 0
pocet = 0
for i from 1 to pocetInt
    lab$ = Get label of interval: 2, i
    if (lab$ <> "") and (index("ieaou", lab$))
        # printline 'lab$'
        t1 = Get start point: 2, i
        t2 = Get end point: 2, i
        trvani = t2 - t1
        soucet = soucet + trvani
        pocet = pocet + 1
    endif
endfor

prumerMS = soucet / pocet * 1000
printline Průměrné trvání je 'prumerMS:2' ms.

Úkol 3: řešení

Předčasné ukončení skriptu

Pokud chceme předčasně ukončit skript, protože např. nebyla splněna nějaká zásadní podmínka, můžeme použít příkaz exitScript: "Zpráva pro uživatele."

clearinfo
pocetTiers = Get number of tiers
if pocetTiers < 2
    exitScript: "TextGrid musí mít alespoň 2 vrstvy. Skutečný počet: ", pocetTiers
endif
printline Počet vrstev je v pořádku, pokračujeme v analýze.
# skript pokračuje...

Konec

Tip: zkuste vytvořit kopii skriptu z Úkolu 3 a modifikovat ho pro výpočet průměrného trvání frikativ.

Zpět na hlavní stranu