Follow along with the video below to see how to install our site as a web app on your home screen.
Huomio: This feature may not be available in some browsers.
Jep, tehtävässä haetaan ihan perus ohjelmointilogiikkaa kielestä välittämättä.Sinun pitää määritellä kaksi uutta muuttujaa: summa ja laskuri joka kertoo montako arvoa on jo annettu. Alusta molemmat nollaksi ja kasvata arvoja kun käyttäjä antaa muun arvon kuin -1.
Tuo convert-funktio on varmaan väärä, kuulostaa että tuo muuntaa kokonaisluvuksi?
E. Listallakin tuon saa toki tehtyä ja pitää käyttää jos tehtävänanto niin käskee. Mutta annetun tehtävän perusteella tarpeetonta.
Niin siis kannattaa varmaan vaan kasvattaa a) laskuria, jossa on kerättyjen lukujen määrä ja b) summaa, jossa on kerätyt luvut yhteenlaskettuna. Sen jälkeen keskiarvo on vaan summa / maara, joka lasketaan sen jälkeen, kun on huomattu, että käyttäjä on syöttänyt -1.Siis onko tämä soveltuva tuohon keskiarvoon:
if(Int32.TryParse(Console.ReadLine(), out input))
{
numbers = input;
sum += numbers;
average += ((decimal)input - average) / (i + 1);
}
Integeriksi muuntaminen ei siis käy.Create a program which is able to calculate and output (as double value, with 3 decimals)
Miten 1.124 + 4.238 on kokonaisluku?
Luetaan tosiaan se tehtävänantoMiten 1.124 + 4.238 on kokonaisluku?
Tän mukaan pitäisi onnistua. Helpommasta en sitten tiedä näillä tiedoilla.Osattaisiinko täällä neuvoa Excelin kanssa? Mulla on työkirjassa vertailtu asioita, jokainen kohde omana sarakkeena ja vertailukriteeri rivinsä. Soluissa on tekstiä ja taustaväri. Saanko jotenkin määritettyä taustaväreille arvot (tekstit säilyttäen)? Eli vihreä tausta on +1, keltainen -2, valkoinen/ei täyttöä 0 jne. Ja arvojen perusteella tulostettua taulukon loppuun sitten pisteet kullekin sarakkeelle, vai meneekö helpommin laskemalla käsin ?
Tein vanilla-esimerkin aiheeseen liittyen:En oikein tunnu löytävän tähän mitään best practices-ohjetta, joten mikä on paras/normaali tapa hoitaa tämä?
Eli minulla on nappi, jolla poistetaan kuva tietokannasta. Tämä toiminnallisuus tietysti kannattaa tehdä JS-funktiolla, jotta näkymää ei tarvitse ladata uudestaan. Joten kannattaako tuo nappi rekisteröidä jollain classilla, siis $("#removebutton").onClick() { ...} vai lisätä onClick buttonin attribuutiksi (onClick="removeImage("/removeCover") jne)? On muutamia erilaisia kuvia ja ne on linkattu eri paikoissa, joten pitää parametrisoida tuo kutsuttava funktio (ensimmäisessä vaihtoehdossa varmaankin sijoittaisin tuon routen data-save-attribuuttiin).
Kumpi on suositeltavampi tapa vai onko tällä väliä?
Nyt on kaunista koodia ...ja samaa mieltä, event listener on siistein vaihtoehto.Tein vanilla-esimerkin aiheeseen liittyen:
Eli IMO helpompaa on rekisteröidä tapahtumankuuntelija classNamen perusteella ja sitten hakea kohdereitti dataset:istä.
$(".btnRemove").on("click", function (e) {
e.preventDefault();
var curr = $(this);
if (confirm("Oletko varma?")) {
img_src = $(this).data("replace");
$.ajax({
type: "POST",
dataType: "json",
url: $(this).data("save"),
data: {
itemId: JSON.stringify(itemId),
},
success: function (data) {
if (curr.attr("replace")) {
$("#image").attr("src", img_src);
}
},
});
}
});
Tämä luettu? .attr() | jQuery API DocumentationAivan ylivoimaisesti eniten tässä JS/DOM-hommassa vituttaa se, että jos on joku ongelma, ja sitä googlaa, saa miljoona eri vaihtoehtoa, joista yksikään ei sitten toimi. Menee ihan vitusti aikaa kun kokeilee kaikki ei-toimivat vaihtoehdot läpi. En tiedä yhtään toista ohjelmointiympäristöä, jossa on lähellekään yhtä paljon rikkinäisiä ohjeita. Nytkin pitäisi niinkin simppeli juttu saada tehtyä kuin tsekattua, että onko elementille tietty attribuutti ja jos on, tehdä jotain. En edes enää tiedä, montako eri vaihtoehtoa olen kokeillut, mutta mikään ei tunnu toimivan. attr() ei tunnu toimivan, eikä hasAttr(). hasAttribute():sta selain valittaa, että ei sellaista olekaan. Ei toimi nämäkään: How to Check If an Element Has Attribute Using jQuery and JavaScript?. Ja tällaistakin syntaksia ehdotettiin: $(this).is("[name]"). Juu, ei.
Toinen juttu on sitten se, että en ole vielä törmännyt kuvaukseen siitä, miten sivun lataus tapahtuu. Lähinnä kiinnostaisi se, että voiko minulle olla lukematon määrä $(document).ready()-funktioita?
Ja vielä: tarvitseeko noiden $(".xxx").on() -tyyppisten jquery-juttujen olla ready():n sisässä vai ajetaanko ne kaikki automaattisesti sivun latauksessa?
Tällä hetkellä olen menossa tällaisessa hässäkässä:
Ilman tuota viimeistä ehtoa homma toimii, joten siinä ei vika ole. Ja tuo curr on tuossa kun alkoi vaikuttaa, että $(this) ei ole jostain syystä enää voimassa success-kohdassa.Koodi:$(".btnRemove").on("click", function (e) { e.preventDefault(); var curr = $(this); if (confirm("Oletko varma?")) { img_src = $(this).data("replace"); $.ajax({ type: "POST", dataType: "json", url: $(this).data("save"), data: { itemId: JSON.stringify(itemId), }, success: function (data) { if (curr.attr("replace")) { $("#image").attr("src", img_src); } }, }); } });
Se ei toimi siksi, että noin määritellyllä funktiolla kuin sinulla tuossa successissa on, on aina oma scopensa, eli this funktion sisällä viittaa aina funktioon itseensä.Ja tuo curr on tuossa kun alkoi vaikuttaa, että $(this) ei ole jostain syystä enää voimassa success-kohdassa.
$(".btnRemove").on("click", function (e) {
e.preventDefault();
if (confirm("Oletko varma?")) {
img_src = $(this).data("replace");
$.ajax({
type: "POST",
dataType: "json",
url: $(this).data("save"),
data: {
itemId: JSON.stringify(itemId),
},
success: (data) => {
if ($(this).attr("replace")) {
$("#image").attr("src", img_src);
}
},
});
}
});
with open(tiedosto, "r") as file:
config = file.read()
pattern_access = re.compile(r'(?<=\nvlan\W100\n.*\portti\W).*')
matches_access = pattern_access.findall(config)
Miten saa Pythonilla seuraavasta tekstistä kolmannen rivin numerot talteen regexin avulla? Saan tuon nimen talteen vlan 100 tekstin alta, mutta kun yritän kolmatta riviä, niin tulee: re.error: look-behind requires fixed-width pattern. Yritin laittaa sulkuja ja noita lookbehindejä erikseen eikä mikään toimi.
Tässä oma koodi:
Python:with open(tiedosto, "r") as file: config = file.read() pattern_access = re.compile(r'(?<=\nvlan\W100\n.*\portti\W).*') matches_access = pattern_access.findall(config)
Teksti on:
vlan 100
name "Nimi"
portti 1,2,3
with open(tiedosto, 'r') as file:
config = file.read()
pattern_access = re.compile(r'(?:vlan|name|portti)\s(.*)(?:\n|\r\n?)?', re.MULTILINE)
matches_access = pattern_access.findall(config)
print(f'{matches_access}')
['100', '"Nimi"', '1,3,5']
Ei ole. Oman ratkaisun löysin Googlettelemalla, kun regexit ei ole oikeen hallussa. Tuossa oli semmonen suunnitelma, että portin numerosta ja vlanista tulee dictionaryn key/value pari (1:100, 2:100, 3:100 jne). Mutta, tuo sinun ratkaisu toimii, koska tuolta listasta saadaan indexillä pomittua arvot ja for loopin kautta siirrettyä tuonne dictionaryyn. Kiitos vastauksesta!Onko erityinen syy käyttää lookbehindia? Helpommalla multiline regexillä Esim.
Python:with open(tiedosto, 'r') as file: config = file.read() pattern_access = re.compile(r'(?:vlan|name|portti)\s(.*)(?:\n|\r\n?)?', re.MULTILINE) matches_access = pattern_access.findall(config) print(f'{matches_access}')
tuottaa:['100', '"Nimi"', '1,3,5']
Tällainen:Miten saa Pythonilla seuraavasta tekstistä kolmannen rivin numerot talteen regexin avulla? Saan tuon nimen talteen vlan 100 tekstin alta, mutta kun yritän kolmatta riviä, niin tulee: re.error: look-behind requires fixed-width pattern. Yritin laittaa sulkuja ja noita lookbehindejä erikseen eikä mikään toimi.
Tässä oma koodi:
Python:with open(tiedosto, "r") as file: config = file.read() pattern_access = re.compile(r'(?<=\nvlan\W100\n.*\portti\W).*') matches_access = pattern_access.findall(config)
Teksti on:
vlan 100
name "Nimi"
portti 1,2,3
txt = "vlan 100\nname \"Nimi\"\n portti 1,2, 123"
r = list(map(int, txt.splitlines()[2].strip().split(" ", 1)[1].split(',')))
import re
txt = "vlan 100\nname \"Nimi\"\n portti 1,2, 123"
m = re.search(".*\n.*\n\s*\w+\s+(\d+)\D+(\d+)\D+(\d+)", txt)
r = []
if m:
for g in range(1, 4):
r.append(m.group(g))
r = list(map(int, r))
#include <iostream>
#include <sstream>
#include <thread>
#include <mutex>
#include <tuple>
#include <climits>
#include <functional>
#include <chrono>
std::mutex mtx_stream;
bool DONE = false;
unsigned long getNextStep(const unsigned long current)
{
return (current % 2) ? (current * 3) + 1 : (current / 2);
}
/**
* @brief Runs the collatz conjecture algorithm for all integers (to the limit)
*
* @param buffer output buffer to save intresting numbers for output formatting
*/
void thread1(std::stringstream &buffer)
{
std::cout << "First thread created, start collatz algorithm" << std::endl;
const unsigned long guard = ULONG_MAX/4;
unsigned long zenith=2, path_record = 0;
unsigned long zenith_update_counter = 0, path_record_update_counter = 0;
bool is_path_record_updated = false;
for (unsigned long seed = 2; seed < guard; seed++){
/* *
if (seed % 1000000 == 0 || path_record_update_counter % 100 == 0){
std::cout \
<< "Current seed: " << seed \
<< ", path record: " << path_record \
<< ", zenith record: " << zenith << std::endl;
}
/* */
for (unsigned long i = seed, path_length = 0; i != 1 && i < guard; path_length++){
i = getNextStep(i);
if (i > zenith) {
zenith = i;
zenith_update_counter++;
}
if (path_length > path_record) {
is_path_record_updated = true;
path_record = path_length;
path_record_update_counter++;
}
}
if (is_path_record_updated){
//std::cout << seed << std::endl;
mtx_stream.lock();
buffer << seed << " " << path_record << std::endl;
mtx_stream.unlock();
is_path_record_updated = false;
}
}
std::cout << "First thread exhausted, exiting" << std::endl;
DONE = true;
}
/** TODO:
* @brief Save records to database (textfile)
*
*/
void thread2(std::stringstream &buffer)
{
std::cout << "Second thread, not implemented" << std::endl;
unsigned int seed, path_length;//std::string seed, path_length;
/* */
while (!DONE){
mtx_stream.lock();
while (buffer >> seed >> path_length) {
//buffer.clear();
std::cout <<"New path length record with seed: " << seed \
<< " (" << path_length << " steps)" << std::endl;
}
mtx_stream.unlock();
std::this_thread::sleep_for(std::chrono::nanoseconds(10000));
}
/* */
std::cout << "Second thread exhausted, exiting" << std::endl;
}
int main(void)
{
std::stringstream buffer;
std::thread first (thread1, std::ref(buffer));
std::thread second (thread2, std::ref(buffer));
first.join();
second.join();
return 0;
}
while (buffer >> seed >> path_length) {
Sulla on siellä kommentoitunaOlen harjoittelemassa ohjelman säikeistämistä ja streamien käyttöä C++:lla. Ideana tässä, että thread1 suorittaisi algoritmia nopeasti ja ottaisi vain talteen mielenkiintoiset luvut myöhempää käsittelyä varten. Thread2 vastaa bufferin lukemisesta ja tässä kehitysvaiheessa ainoastaan tulostaa ne ruudulle formatoituina.
Ongelmana on, että bufferin lukeminen ja tulostaminen lakkaa toimimasta jo muutaman iteraation jälkeen:
First thread created, start collatz algorithm
Second thread, not implemented
New path length record with seed: 3 (6 steps)
New path length record with seed: 6 (7 steps)
New path length record with seed: 7 (15 steps)
New path length record with seed: 9 (18 steps)
New path length record with seed: 18 (19 steps)
New path length record with seed: 25 (22 steps)
New path length record with seed: 27 (110 steps)
New path length record with seed: 54 (111 steps)
New path length record with seed: 73 (114 steps)
New path length record with seed: 97 (117 steps)C++:#include <iostream> #include <sstream> #include <thread> #include <mutex> #include <tuple> #include <climits> #include <functional> #include <chrono> std::mutex mtx_stream; bool DONE = false; unsigned long getNextStep(const unsigned long current) { return (current % 2) ? (current * 3) + 1 : (current / 2); } /** * @brief Runs the collatz conjecture algorithm for all integers (to the limit) * * @param buffer output buffer to save intresting numbers for output formatting */ void thread1(std::stringstream &buffer) { std::cout << "First thread created, start collatz algorithm" << std::endl; const unsigned long guard = ULONG_MAX/4; unsigned long zenith=2, path_record = 0; unsigned long zenith_update_counter = 0, path_record_update_counter = 0; bool is_path_record_updated = false; for (unsigned long seed = 2; seed < guard; seed++){ /* * if (seed % 1000000 == 0 || path_record_update_counter % 100 == 0){ std::cout \ << "Current seed: " << seed \ << ", path record: " << path_record \ << ", zenith record: " << zenith << std::endl; } /* */ for (unsigned long i = seed, path_length = 0; i != 1 && i < guard; path_length++){ i = getNextStep(i); if (i > zenith) { zenith = i; zenith_update_counter++; } if (path_length > path_record) { is_path_record_updated = true; path_record = path_length; path_record_update_counter++; } } if (is_path_record_updated){ //std::cout << seed << std::endl; mtx_stream.lock(); buffer << seed << " " << path_record << std::endl; mtx_stream.unlock(); is_path_record_updated = false; } } std::cout << "First thread exhausted, exiting" << std::endl; DONE = true; } /** TODO: * @brief Save records to database (textfile) * */ void thread2(std::stringstream &buffer) { std::cout << "Second thread, not implemented" << std::endl; unsigned int seed, path_length;//std::string seed, path_length; /* */ while (!DONE){ mtx_stream.lock(); while (buffer >> seed >> path_length) { //buffer.clear(); std::cout <<"New path length record with seed: " << seed \ << " (" << path_length << " steps)" << std::endl; } mtx_stream.unlock(); std::this_thread::sleep_for(std::chrono::nanoseconds(10000)); } /* */ std::cout << "Second thread exhausted, exiting" << std::endl; } int main(void) { std::stringstream buffer; std::thread first (thread1, std::ref(buffer)); std::thread second (thread2, std::ref(buffer)); first.join(); second.join(); return 0; }
Olen kokeillut tätä mutexilla ja ilman, eikä sillä ole mitään vaikutusta. Mielenkiintoisena yksityiskohtana on tulostettavien rivien määrä - eri suorituskerroilla saan kaikkea 5:n ja 15:sta rivin väliltä.
Onko ideoita mitä teen väärin?
//buffer.clear();
mtx_stream.lock();
while (buffer >> seed >> path_length) {
std::cout <<"New path length record with seed: " << seed \
<< " (" << path_length << " steps)" << std::endl;
}
buffer.clear();
mtx_stream.unlock();
Vaihdat css-luokan .card väriä, et yksittäisten korttien väriä. => kaikilla korteilla loopin viimeisen kortin väri.Terve! Oon hetken paininut henkilökohtaisen harjoitteluprojektin kanssa. Tuon APIn kautta saan kyseisten tavaroiden "rarityn" haettua. Haluaisin tavaran rarityn mukaan määrittää kortille taustavärin. Tällä hetkellä olen koittanut käyttää if elseä siihen värin hakemiseen. (Löytyy tuon codepenistä kommentoituna.)
Täytyisi varmaan käyttää jonkinnäköistä silmukkaa, koska tän hetkisellä ratkaisulla kaikille korteille tulee sama väri. Consoli kuitenkin kertoo että se hakee ne oikeat arvot sieltä apista.
Oma taito ei riitä vielä saamaan silmukkaa toimimaan kun kyseessä on api jossa on monia objekteja. Osaisiko kukaan auttaa/Tökkästä oikeaan suuntaan?
Kiitos vastauksesta! Sain ongelmaan ratkaisun Stack overflown puolella. Linkki jos joku joskus painii saman ongelman kanssa.Vaihdat css-luokan .card väriä, et yksittäisten korttien väriä. => kaikilla korteilla loopin viimeisen kortin väri.
Ottaa bufferista kaksi whitespacella erotettua arvoa ja asettaa ne muuttujiin seed ja path_length. Tämän jälkeen while-silmukka evaluoi edellisen operaation paluuarvon - jonka sisältöä en näköjään ole kunnolla sisäistänyt. (katso alla oleva lainaus)Minua kiinostaa rivi:
while (buffer >> seed >> path_length) {
Mitä tämä tekee? C++ doc: while ( expression ) ;
Kiitos todella paljon selventävästä vastauksesta, alkoi pelittämään.Ja tuo clear tarvitaan siis sen takia, että thread1 ei suostu kirjoittamaan bufferiin, jos sen tila on "eof" eli end-of-file (tai oikeastaan end-of-stream). Clearin jälkeen tilasta tulee jälleen "good" jolloin bufferiin voi kirjoittaa.
edit: Tarkalleen ottaen stringstreamin tilat on vähän monimutkaisempia kuin yllä esitetty yksinkertaistettu good vs.eof. On mahdollista löytää streamin loppu siten, että tila säilyy hyvänä. Mutta yllä olevassa koodissa sen ei pitäisi koskaan tapahtua, koska streamin lopun osuessa kohdalle seediin ja path_lengthiin ei voi kirjoittaa, eli eof on käytännössä sama asia kuin fail, joka on käytännnössä sama kuin ei-good.
Juu, itse täs kännyllä, nii ei ole esimerkkiä antaa. Mut ton sun koodin perusteella, ku värit bäkkäristä tulee ja on tiedossa, nii voisit esim. niitä vastaavat css-luokat tehdä ja asettaa kortille suoraan ilman ehtolauseita. Esim. color-common, color-grey jne. Muutenki semmonen yleinen värisetti hyvä lähestymistapa. Esim.color-primary, color-secondary, color-grey-1,color-grey-2,color-card-1,color-card-2 jne. Helppo sit jälkikäteen muutella.Kiitos vastauksesta! Sain ongelmaan ratkaisun Stack overflown puolella. Linkki jos joku joskus painii saman ongelman kanssa.
Oli minulta vähän huonosti selitetty minun ongelma. Eli, tilanne on semmoinen että minulla on config-tiedosto, mistä pitää lukea nuo rivit ja samassa tiedostossa on muita samanlaisia rivejä. Olen saanut jo luetua dictionaryyn key:value pariksi vlan id:n ja nimen (100:vlan 100, 200:vlan 200, 300:vlan 300). Nyt tästä dictionarystä luetaan key valuet (for loopissa) ja lisätään se muuttujan avulla tuonne regex rimpsun sisälle, että se hakee tietyn vlanin alta nuo portit. Sitten ne (untagged/tagged) taas käsitellään for loopissa siten, että portin numero menee keyksi ja vlan id valueksi omissa dictionareissa. @Barbarossa ehdotus multilinestä oli hyvä, mutta en keksinyt itse järkevää tapaa miten saan tiedot oikein, jos vlan xxx rivin alta puuttuu joku rivi (name, untagged tai tagged).Tällainen:
Python:txt = "vlan 100\nname \"Nimi\"\n portti 1,2, 123" r = list(map(int, txt.splitlines()[2].strip().split(" ", 1)[1].split(',')))
... etsii merkkijonon 'txt' kolmannelta riviltä rivin alun mahdollisten blankkojen (strip) jälkeen ensimmäisen blankkojonon jälkeisestä rivin lopusta pilkkujen erottamat jonot, konvertoi ne kokonaisluvuiksi ja antaa tuloksen listana.
Näin minä sen tekisin. Jos jostain syystä (?) on pakko käyttää regexiä, niin esim. näin saisi saman tuloksen:
Python:import re txt = "vlan 100\nname \"Nimi\"\n portti 1,2, 123" m = re.search(".*\n.*\n\s*\w+\s+(\d+)\D+(\d+)\D+(\d+)", txt) r = [] if m: for g in range(1, 4): r.append(m.group(g)) r = list(map(int, r))
Tuo siis aluksi skippaa kaksi riviä ja kolmannen rivin alusta ensin mahdolliset blankot, sitten vähintään yhden ei-whitespacen ja sen jälkeiset blankot, ja etsii loppurivistä kolme numerojonoa, joiden välisssä on ei-numeroita.
Nuo siis toimivat jos ja vain jos niitä lukuja etsitään nimenomaan kolmannelta riviltä, ja lukuja on rivillä regex-tapauksessa vähintään kolme. Eikä ole väliä sillä, mitä rivin alussa lukee.
Oli minulta vähän huonosti selitetty minun ongelma. Eli, tilanne on semmoinen että minulla on config-tiedosto, mistä pitää lukea nuo rivit ja samassa tiedostossa on muita samanlaisia rivejä. Olen saanut jo luetua dictionaryyn key:value pariksi vlan id:n ja nimen (100:vlan 100, 200:vlan 200, 300:vlan 300). Nyt tästä dictionarystä luetaan key valuet (for loopissa) ja lisätään se muuttujan avulla tuonne regex rimpsun sisälle, että se hakee tietyn vlanin alta nuo portit. Sitten ne (untagged/tagged) taas käsitellään for loopissa siten, että portin numero menee keyksi ja vlan id valueksi omissa dictionareissa. @Barbarossa ehdotus multilinestä oli hyvä, mutta en keksinyt itse järkevää tapaa miten saan tiedot oikein, jos vlan xxx rivin alta puuttuu joku rivi (name, untagged tai tagged).
Eli tiedosto näyttää tältä:
vlan 100
name "vlan 100"
untagged 1,3,4
tagged 27,28
vlan 200
name "vlan 200"
untagged 2,4,6
tagged 27,28
vlan 300
name "vlan 300"
untagged 7,9,11
tagged 27,28
txt = 'vlan 100\nname "vlan 100"\nuntagged 1,3,4\ntagged 17,18\n\nvlan 200\nname "vlan 200"\nuntagged 1,3,4\ntagged 27,28\n\nvlan 300\nname "vlan 300"\ntagged 37,38'
vlans = txt.split("\n\n")
vlan_list = []
for vlan in vlans:
lines = vlan.split("\n")
prop_dict = {}
for line in lines:
key, value = line.split(" ", 1)
prop_dict[key] = value
vlan_list.append(prop_dict)
print(vlan_list)
[
{'vlan': '100', 'name': '"vlan 100"', 'untagged': '1,3,4', 'tagged': '17,18'},
{'vlan': '200', 'name': '"vlan 200"', 'untagged': '1,3,4', 'tagged': '27,28'},
{'vlan': '300', 'name': '"vlan 300"', 'tagged': '37,38'}
]
Juu, oli todella huonosti selitetty. Eikä uusi selitys ole juurikaan parempi, kun et vieläkään kuvaa mitä oikeasti haluat saada aikaan. Edupin ehdotus on periaatteessa toimiva, mutta se sekoaa jos riviryhmien välissä on useampia tyhjiä rivejä, tai jos rivien alussa on tyhjää, eikä se tee mitään niille porttinumeroiksi olettamilleni tagged/untagged-rivien luvuille. Mitä niille pitäisi tehdä?Oli minulta vähän huonosti selitetty minun ongelma. Eli, tilanne on semmoinen että minulla on config-tiedosto, mistä pitää lukea nuo rivit ja samassa tiedostossa on muita samanlaisia rivejä. Olen saanut jo luetua dictionaryyn key:value pariksi vlan id:n ja nimen (100:vlan 100, 200:vlan 200, 300:vlan 300). Nyt tästä dictionarystä luetaan key valuet (for loopissa) ja lisätään se muuttujan avulla tuonne regex rimpsun sisälle, että se hakee tietyn vlanin alta nuo portit. Sitten ne (untagged/tagged) taas käsitellään for loopissa siten, että portin numero menee keyksi ja vlan id valueksi omissa dictionareissa. @Barbarossa ehdotus multilinestä oli hyvä, mutta en keksinyt itse järkevää tapaa miten saan tiedot oikein, jos vlan xxx rivin alta puuttuu joku rivi (name, untagged tai tagged).
Eli tiedosto näyttää tältä:
vlan 100
name "vlan 100"
untagged 1,3,4
tagged 27,28
vlan 200
name "vlan 200"
untagged 2,4,6
tagged 27,28
vlan 300
name "vlan 300"
untagged 7,9,11
tagged 27,28
Juu, oli todella huonosti selitetty. Eikä uusi selitys ole juurikaan parempi, kun et vieläkään kuvaa mitä oikeasti haluat saada aikaan. Edupin ehdotus on periaatteessa toimiva, mutta se sekoaa jos riviryhmien välissä on useampia tyhjiä rivejä, tai jos rivien alussa on tyhjää, eikä se tee mitään niille porttinumeroiksi olettamilleni tagged/untagged-rivien luvuille. Mitä niille pitäisi tehdä?
Setämäisesti ehdotan, että unohda hetkeksi mitä tiedät python-dictionaryistä ja regular expressionneista, ja kuvaa vaikkapa ihan suomen kielellä syötteen ja halutun tulosteen sisältö ja rakenne.
import shlex
import os
def to_dict(l):
i = iter(l)
return dict(zip(i, i))
def read_config(cf):
with open(cf, 'r') as file:
config = file.read().strip()
blocks = [to_dict(shlex.split(block)) for block in config.split(os.linesep*2)]
config = {}
for b in blocks:
vlan = int(b.pop('vlan'))
config[vlan] = b
return config
On. Tämä on tekstipohjainen konfiguraatio, missä on näitten rivien ylä- / alapuolella muita globaaleja komentoja, niin pitäisi poimia juuri nuo rivit. Kiitoksia kaikille vastanneille jo etukäteen kärsivällisyydestä.Onko sulla joku erityinen syy käyttää regexiä tässä?.
Minun pitää lukea tiedostosta nuo rivit ja muuttaa ne eri muotoon, mitkä kirjoitetaan toiseen tiedostoon. Eli tästä tulee ohjelma mikä muuttaa konfiguration toiseen laitevalmistajan muotoon. Olisin pistänyt tähän mallikonfiguraation, mutta ei ollut yhtään tallessa.Juu, oli todella huonosti selitetty. Eikä uusi selitys ole juurikaan parempi, kun et vieläkään kuvaa mitä oikeasti haluat saada aikaan. Edupin ehdotus on periaatteessa toimiva, mutta se sekoaa jos riviryhmien välissä on useampia tyhjiä rivejä, tai jos rivien alussa on tyhjää, eikä se tee mitään niille porttinumeroiksi olettamilleni tagged/untagged-rivien luvuille. Mitä niille pitäisi tehdä?
Setämäisesti ehdotan, että unohda hetkeksi mitä tiedät python-dictionaryistä ja regular expressionneista, ja kuvaa vaikkapa ihan suomen kielellä syötteen ja halutun tulosteen sisältö ja rakenne.
On. Tämä on tekstipohjainen konfiguraatio, missä on näitten rivien ylä- / alapuolella muita globaaleja komentoja, niin pitäisi poimia juuri nuo rivit. Kiitoksia kaikille vastanneille jo etukäteen kärsivällisyydestä.
txt = 'vlan 100\nname "vlan 100"\nuntagged 1,2,3\ntagged 11,12\n\nvlan 200\nname "vlan 200"\nuntagged 4,5\ntagged 21,22\n\nvlan 300\nname "vlan 300"\ntagged 31,32,33\n\nvlan 400\ntagged 41,42'
pattern = re.compile(r'vlan\s(\w+)(?:\nname\s"(.+?)")?(?:\nuntagged\s([\w,]*))?(?:\ntagged\s([\w,]*))?', re.MULTILINE)
print(re.findall(pattern, txt))
[
('100', 'vlan 100', '1,2,3', '11,12'),
('200', 'vlan 200', '4,5', '21,22'),
('300', 'vlan 300', '', '31,32,33'),
('400', '', '', '41,42')
]
Tuo menee sekaisin, jos vaikka lisäät txtiin yhden ylimääräisen blankon ensimmäisen vlan-sanan jälkeen. Pelkkä \s matchaa vain _yhden_ spacen. Ja niin edelleen. Ihan yleisestikin neuvoisin olettamaan inputin laadusta mahdollisimman vähän, etenkin jos input on ihmisen tekemä. Ja sitten se MULTILINE-flagi: Se vaikuttaisi erikoismerkkien ^ ja $ (rivin alku ja loppu) tulkintaan, mutta kun et näitä lainkaan käytä, niin flagi on merkityksetön.Okei, no tossa sulle nyt regex-hirviö tuohon mikä perkaa nuo kaikki sulle johonkin rakenteiseen muotoon mistä saat ne eteenpäin:
Python:txt = 'vlan 100\nname "vlan 100"\nuntagged 1,2,3\ntagged 11,12\n\nvlan 200\nname "vlan 200"\nuntagged 4,5\ntagged 21,22\n\nvlan 300\nname "vlan 300"\ntagged 31,32,33\n\nvlan 400\ntagged 41,42' pattern = re.compile(r'vlan\s(\w+)(?:\nname\s"(.+?)")?(?:\nuntagged\s([\w,]*))?(?:\ntagged\s([\w,]*))?', re.MULTILINE) print(re.findall(pattern, txt))
Koodi:[ ('100', 'vlan 100', '1,2,3', '11,12'), ('200', 'vlan 200', '4,5', '21,22'), ('300', 'vlan 300', '', '31,32,33'), ('400', '', '', '41,42') ]
Toi on edelleen vähän jäätävä tapa toteuttaa tuo, mutta varmaan auttanee pääsemään eteenpäin. Käytännössä tuolla siis luodaan non-capturing groupit tuolla (?: ) -notaatiolla, ja sen ko. non-capturing-groupin perässä ? sitä varten jos ko. arvoa ei aina konffista löydy. Niiden non-capturing-groupien sisällä on sitten perus capturing group mikä poimii ne halutut arvot talteen, jos se ulompi ryhmä nyt sitten on olemassa.
EDIT: Ainiin, nimikin sai puuttua. Muokattu pikkusen tuota, niin että senkin saa skipata. Vai oliko sitä nyt sitten olemassakaan lopulta?
txt = ('vlan 100\nname "vlan 100"\nuntagged 1,2,3\ntagged 11,12\n\n'
' vlan 200\nname "vlan 200"\nuntagged 4,5\ntagged 21,22\n \n\n'
'Vlan 300\nname "vlan 300"\ntagged 31,32,33\n\n'
'vlan 400\ntagged 41,42')
vlan = {} # riviniput
id = None # nipun tunnus
for line in (x.strip() for x in txt.splitlines()):
# riveistä on alku- ja loppublankot siivottu
if not line:
# tyhjä rivi lopettaa nipun
# tyhjiä voi olla useita peräkkäin
id = None
continue
else:
# ei-tyhjä rivi lisätään vlan-dictiin
k, v = line.split(" ", 1)
k = k.lower()
v = v.strip()
# nipun ensimmäisenä pitää olla 'vlan id'
if k == "vlan":
if id:
# nipun alku on jo nähty, sivuutetaan
# (voisi olla myös fataali)
continue
id = v
vlan[id] = {}
elif id and k in ("name", "tagged", "untagged"):
# vain jos nipun alku jo nähty
if k in ("tagged", "untagged"):
# arvoksi int-lista
try:
v = list(map(int, v.split(',')))
except ValueError:
# sivuutetaan rivi, voisi olla myös fataali
continue
vlan[id][k] = v
# muut rivit sivuutetaan
for k, v in vlan.items():
print(k, v)
Tuo menee sekaisin, jos vaikka lisäät txtiin yhden ylimääräisen blankon ensimmäisen vlan-sanan jälkeen. Pelkkä \s matchaa vain _yhden_ spacen. Ja niin edelleen. Ihan yleisestikin neuvoisin olettamaan inputin laadusta mahdollisimman vähän, etenkin jos input on ihmisen tekemä. Ja sitten se MULTILINE-flagi: Se vaikuttaisi erikoismerkkien ^ ja $ (rivin alku ja loppu) tulkintaan, mutta kun et näitä lainkaan käytä, niin flagi on merkityksetön.
En osaa niin hyvin regexiä että viitsisin pelkästään sen keinoin yrittää inputtia siivota. Pythonilla se sensijaan sujuisi esim. näin:
Python:txt = ('vlan 100\nname "vlan 100"\nuntagged 1,2,3\ntagged 11,12\n\n' ' vlan 200\nname "vlan 200"\nuntagged 4,5\ntagged 21,22\n \n\n' 'Vlan 300\nname "vlan 300"\ntagged 31,32,33\n\n' 'vlan 400\ntagged 41,42') vlan = {} # riviniput id = None # nipun tunnus for line in (x.strip() for x in txt.splitlines()): # riveistä on alku- ja loppublankot siivottu if not line: # tyhjä rivi lopettaa nipun # tyhjiä voi olla useita peräkkäin id = None continue else: # ei-tyhjä rivi lisätään vlan-dictiin k, v = line.split(" ", 1) k = k.lower() v = v.strip() # nipun ensimmäisenä pitää olla 'vlan id' if k == "vlan": if id: # nipun alku on jo nähty, sivuutetaan # (voisi olla myös fataali) continue id = v vlan[id] = {} elif id and k in ("name", "tagged", "untagged"): # vain jos nipun alku jo nähty if k in ("tagged", "untagged"): # arvoksi int-lista try: v = list(map(int, v.split(','))) except ValueError: # sivuutetaan rivi, voisi olla myös fataali continue vlan[id][k] = v # muut rivit sivuutetaan for k, v in vlan.items(): print(k, v)
Tuossa siis syntyy dictionaryjen dictionary. Mutta edelleenkään en tiedä, miten tästä edetään siihen haluttuun lopputulokseen. Kun ei ole kerrottu mikä vastaa mitä.
+1Edelleen olen sitä mieltä että tuon toteuttaminen on regexillä typerää, mutta tuo nyt ainakin tekee sen mitä on pyydetty.