Diskuze: Přepsání určitých textů/stringů v souboru
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.


DarkCoder:30.5.2021 2:59
Z tvého popisu usuzuji, že se snažíš počeštit cizí aplikaci.
Ano, smyslem celého snažení je vygenerování nového XML souboru, který později přejmenuješ na název cílového souboru. Jediné co potřebuješ znát je jak vypadá struktura XML souboru, že texty které budeš nahrazovat jsou uzavřeny mezi identifikovanými bloky.
Realizace je jednoduchá. V cílovém souboru postupně procházíš jednotlivé bloky a podle identifikátoru je dohledáváš ve zdrojovém souboru. Před vyhledáním provedeš analýzu na akceptované formátování. Pokud bude vše ok, najdeš blok ve zdrojovém souboru a zapíšeš ho do nového souboru. Pokud formátování nebude dle tvých představ, celý blok z cílového souboru zapíšeš do nového souboru. Vše co nenajdeš ve zdrojovém souboru tak z cílového souboru do nového opíšeš.
Dost úsilí ale vydáváš na vytvoření XML zdrojového souboru. Dobré by bylo si z cílového souboru vytáhnout texty mezi bloky, k těm přidat překlad a tyto přeložené texty implementovat do nového souboru postupem, který jsem výše uvedl. Vyhneš se tak zbytečnému vytváření XML struktury, kterou za tebe může vygenerovat program.
DarkCoder>
Prostě mám dva XML soubory, jeden počeštěný a druhý v angličtině,
jenže v tom počeštěném jsou nějaké stringy, jež nemá ten anglický a v
tom anglickém jsou zase stringy, jež nejsou v tom českém, tak chci právě
ty nepočeštěné zachovat a zbylé stringy, jež se budou shodovat dle daných
ID stringů.
Také chci zachovat formát odřádkování; tj. aby mi všechny stringy nehodil
do jednoho řádku, ale bylo zachované i to klasické odřádkování.
Problém ale je, že vůbec netuším, jak takový kod mám napsat, takže
bych byl moc rád, kdyby mi někdo s tím pomohl, tj. de facto ho napsal za mě.
Teprve se C# učím a nevím, jestli tady bych a hlavně nevím, jak bych měl
použít serializaci a deserializaci.
... a to jsem si o tom pár návodů a stránek přečetl, ale stejně jsem z
toho totálně tumpachový.
DarkCoder:30.5.2021 13:21
K realizaci potřebuješ znát akorát práci se souborem (otevření, zavření, čtení, zápis) a práci s řetězci.
V cílovém souboru hledáš bloky, uchováváš si jejich pozici a obsah. Vše co je vně opisuješ do nového souboru. Když budeš číst cílový soubor znak po znaku, tak zjistíš, že znaky nových řádků jsou mimo bloky a ty tak přímo zapisuješ do nového souboru a zachováš tak formátování. Nemůže se tedy stát, že jednotlivé bloky budou v novém souboru za sebou.
Když začneš číst cílový soubor, zjistíš že první znak je otevřená hranatá závorka, což značí, že si narazil na hlavičku bloku. Najdeš koncovou hranatou závorku. Obsah uvnitř si uložíš, můžeš klidně se závorkami. Zjistíš validitu, koncový blok je na konci stejného řádku, je tedy ok. Vygeneruješ si konec bloku (přidáním zpětného lomítka k hlavičce a oříznutím zbytku) a uchováš si pozici koncové hranaté závorky. Nyní prohledáváš zdrojový soubor a hledáš hlavičku kterou jsi si uložil. Pokud ji najdeš tak najdeš konec bloku a vše uvnitř včetně bloku zapíšeš do nového souboru. Pokud nenajdeš, tak opíšeš uložený blok z cílového souboru do nového.
Máš tedy uloženo:
<string id ="1">
a pozici koncové hranaté závorky ukončovacího bloku
Vygeneruješ koncový blok
</string>
Ve zdrojovém souboru najdeš
<string id ="1"> bojovník </string>
a toto celé zapíšeš do nového souboru.
Nyní pokračuješ v čtení cílového souboru. Narážíš na znak nového
řádku. Jelikož je vně bloků, tak ho zapíšeš do nového souboru.
Takto pokračuješ dál a dál. Při čtení
<string id ="7">
Zjistíš, že obsah není validní, jeho bloky nejsou na stejném řádku. Tak ho z cílového souboru opíšeš do nového souboru se všemi formátovacími znaky.
Do nového souboru pak zapíšeš zbylý řádek ze zdrojového souboru čímž dostaneš výslednou podobu nového XML souboru.
<string id ="1"> bojovník </string>
<string id ="2"> mág </string>
<string id ="3"> zloděj </string>
<string id ="4"> paladin </string>
<string id ="5"> klerik </string>
<string id ="6"> druid </string>
<string id ="7"> science
human-science.</string>
<string id ="12"> Deník </string>
Nakonec jeho jméno pojmenuješ jménem cílového souboru. To je celé..
Jak to vysvětluješ, tak to vypadá snadně a jednoduše.
Jenže, ačkoli sice umím pracovat s načtením a s uložením souborů, tak
stejně to ostatní je pro mě už Vyšší Dívčí.
Sice už jsem programoval jeden malý prográmek, sic ve WinFormu, ale ten se
vůbec netýkal XML ani vše kolem toho.
Na tohle bych vážně potřeboval mít už hotový zdrojový kod od někoho
jiného a z něj pak se učil chápat práci s XML.
Já vím, že je hodně stránek s kody pro XML a s jejich popisem, ale nenašel
jsem žádný, který by řešil zrovna tuhle situaci.
Jsem jen začínající programátor v C#, který se to učí jen jako samouk z
CodeSource, přes strýčka Gúgla a dalších lidí a také stylem
pokus-omyl.
Přesto jsou oblasti, jež vůbec nejsem s to pochopit a hlavně vytvořit
správný kod, ani jak začít.
DarkCoder:30.5.2021 17:32
Pokud umíš pracovat se soubory a řetězci, pak si schopen to vyřešit. Nic víc nepotřebuješ. Zapomeň na pojem XML, tím že si se s ním nesetkal pak v tobě vytváří blok, že nevíš co dělat. Nahlížej na to jako na prostou posloupnost znaků uvozenou bloky s identifikátory.
Začni tím že vynajdeš hlavičku uvozeného textu (včetně ostrých závorek) a uložíš si ji do paměti.
Že si samouk není nic omezujícího. Mě také nikdo neučil, v C# jsem nenapsal jedinou řádku, ale přesto do detailu od pohledu vím jak to řešit. Vše je o zkušenostech, které také s rostoucím počtem napsaných řádků kódu získáš. Hlavní je se toho nebát..
No, umím jen načíst klas. TeXTový soubor, s ním pracovat a pak ho zase
uložit, ale už nevím, jak pracovat se strukturovaným souborem.
Ani nevím, jak mám zjistit validitu a vše, co popisuješ.
Prostě nevím, jak a čím začít a hlavně vůbec netuším, jak takový kod
má vypadat a jak ho vytvořit.
Já jsem spíše servisní technik IT než programátor.
Děkuji ti za všechny rady, ale bez nějakého už hotového kodu jsem nahraný
a totálně mimo.
Rád bych se naučil aspon C#, ale z toho, co ted už vím, tak jsem schopen -
aspon z části - to pochopit už z hotového kodu a ten pak dál upravovat a
doplnovat dle potřeby; ale bez základu nemám dál co a jak stavět.
Petr Štechmüller:30.5.2021 19:31
Ahoj,
čtení strukturovaného souboru znak po znaku, když má jazyk již
implementované parsery je dost nešťastné řešení.
V C# jsem dělal kdysi dávno, teď dělám v Javě, ale to je "to samé". Z
článků tady na síti by jsi se dozvěděl, že existují alespoň dva
způsoby pro čtení XML::
- SAX - https://www.itnetwork.cz/…-zapis-saxem, https://www.itnetwork.cz/…ni-xml-saxem
- DOM - https://www.itnetwork.cz/…rial-xml-dom
Ve svém příkladu uvedu použití DOM parseru. Sice to bude v Javě, ale pro C# to bude hodně obdobné. A jak říkáš, pokud teprve začínáš, tak si k tomu sedni a zkoušej. Tím se toho nejvíc naučíš. Když něco nebudeš vědět, zeptej se tu. Vždy se tu najde alespoň jeden člověk, který už podobný problém řešil, či tě alespoň dokáže návést na správné řešení.
Tento kus kódu mi v Javě vytvoří nový DOM parser a vrátí kořenový element v XML dokumentu.
public Element load(Path path) throws IOException, ParserConfigurationException, SAXException {
LOGGER.info("Načítám XML soubor na cestě: {}.", path.toString());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(path.toFile());
return doc.getDocumentElement();
}
Na to mám navazující parsující metodu, která mi načte celé XML do paměti do mnou definované struktury:
public XmlNode parse(Element xmlRootElement) {
int depth = 0;
XmlNode rootNode = new XmlNode(xmlRootElement.getNodeName(), depth);
readAttributes(rootNode, xmlRootElement);
recursiveRead(rootNode, xmlRootElement, depth + 1);
return rootNode;
}
protected void readAttributes(XmlNode rootNode, Node xmlRootElement) {
NamedNodeMap attributes = xmlRootElement.getAttributes();
if (attributes == null) {
return;
}
for (int i = 0; i < attributes.getLength(); i++) {
Attr item = (Attr) attributes.item(i);
rootNode.attributes.add(new XmlNodeAttribute(rootNode, item.getName(), item.getValue()));
}
}
protected boolean recursiveRead(XmlNode rootNode, Node xmlRootElement, int depth) {
NodeList childNodes = xmlRootElement.getChildNodes();
boolean hasElementNodes = false;
List<String> comments = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
switch (item.getNodeType()) {
case Node.ELEMENT_NODE:
hasElementNodes = true;
Element element = (Element) item;
XmlNode leaf = new XmlNode(element.getNodeName(), depth, rootNode);
leaf.comments.addAll(comments);
comments.clear();
readAttributes(leaf, element);
if (!recursiveRead(leaf, element, depth + 1)) {
leaf.content = element.getTextContent();
}
rootNode.children.add(leaf);
break;
case Node.COMMENT_NODE:
comments.add(item.getNodeValue());
break;
case Node.TEXT_NODE:
if ("#text".equals(item.getNodeName())) {
continue;
}
break;
}
}
return hasElementNodes;
}
Ta struktura je definována velmi jednoduše za pomoci třídy XmlNode:
public class XmlNode {
public final XmlNode parent;
public final int depth;
public final List<XmlNodeAttribute> attributes = new ArrayList<>();
public final List<String> comments = new ArrayList<>();
public final List<XmlNode> children = new LinkedList<>();
public String name;
public String content;
private final String depthSpace;
public XmlNode(String name, int depth) {
this(name, depth, null);
}
public XmlNode(String name, XmlNode parent) {
this(name, parent.depth + 1, parent);
}
public XmlNode(String name, int depth, XmlNode parent) {
this.name = name;
this.depth = depth;
this.parent = parent;
this.content = "";
depthSpace = " ".repeat(depth);
}
Tím si načteš oba dva překlady - český a anglický. Pak budeš procházet oba grafy do hloubky. No a na základě nějaké tvé logiky budeš sestavovat nový třetí (výsledný) graf. Ten se opět bude skládat z XmlNodů. Nakonec vše zase zpět převedeš na XML:
@Override
public Document serialize(XmlNode rootNode) throws ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element rootElement = document.createElement(rootNode.name);
document.appendChild(rootElement);
writeComments(document, rootElement, rootNode.comments);
writeAttributes(rootElement, rootNode.attributes);
serialize(document, rootElement, rootNode.children);
return document;
}
private void serialize(Document document, Element rootElement, List<XmlNode> children) {
for (XmlNode child : children) {
Element childElement = document.createElement(child.name);
rootElement.appendChild(childElement);
writeComments(document, childElement, child.comments);
writeAttributes(childElement, child.attributes);
if (child.children.isEmpty()) {
childElement.setTextContent(child.content);
} else {
serialize(document, childElement, child.children);
}
}
}
private void writeComments(Document document, Element element, List<String> comments) {
for (String comment : comments) {
Comment c = document.createComment(comment);
element.getParentNode().insertBefore(c, element);
}
}
private void writeAttributes(Element element, List<XmlNodeAttribute> attributes) {
for (XmlNodeAttribute attribute : attributes) {
element.setAttribute(attribute.key, attribute.value);
}
}
Na konec bych chtěl říct. Je to úplně opačný směr, než ti nabízí
kolega. Je jen na tobě, jestli ten kód vezmeš a v rámci svého snažení ho
přetransformuješ do C# tak, aby ti to fungovalo dle očekávání.
Pokud budeš mít ke kódu jakékoliv připomínky, určitě se ptej, rád je
zodpovím.
Kód dávám k dispozici s tím, že je mi jedno, jak s ním kdokoliv naloží,
ale neručím za následky použití tohoto kódu.
Hodně štěstí.
DarkCoder:30.5.2021 21:32
XML soubor je určitá forma textového souboru. Jediné v čem se to nepatrně liší je způsob vyhledávání a vytahování dat. Nicméně použité nástroje jsou stále stejné.
Podoba nového souboru bude podobná cílovému souboru, pouze s odlišnými daty. Proto můžeš postupovat sekvenčně skrz cílový soubor, hledat identifikátor, dohledat jej ve zdrojovém souboru a aktualizovat nový soubor. Jelikož podoba cílového a zdrojového souboru souboru je obdobná, je záměna dát přímočará a rychlá. Nemusíš procházet celý soubor znova.
Abys viděl jak to funguje a viděl úzkou souvislost, zpracuj si následující příklad:
Máš řetězec
abc12defg345hi678jklmnop9012rstuv3wxyz
Nahraď všechna lichá čísla písmenem 'X' a všechna sudá čísla písmenem 'Y'.
Smyslem tohoto příkladu je poznat jaké úkony jsou třeba pro vyřešení příkladů a vidět souvislosti s tím co chceš udělat.
Jinak nic Ti nebrání v tom naučit se alespoň základy programování, třeba v jazyce C#. Poznáš tak jak vypadá takový program, čím začínat apod. Jak s tím budeš experimentovat, budeš vnímat souvislosti a budeš později schopen psát komplikovanější programy, které Ti mohou v lecčem dosti usnadnit práci. C# je hodně rozšířený, pro začínající určitě vhodný. Díky tomu v tom nezůstaneš sám a jak už tu bylo zmíněno, vždy se tu najde někdo kdo Ti poradí a celé to tak bude jednodušší.
Nakonec jsem našel na webu program, který to už umí, takže už jsem
neměl důvod vytvářet nový.
Přesto všem, kteří reagovali na můj dotaz a chtěli mi pomoci, moc děkuji.
+5 Zkušeností

Zobrazeno 10 zpráv z 10.