Ein String im String suchen.
- Xin
- nur zu Besuch hier
- Beiträge: 8859
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Ein String im String suchen.
Auch wenn ihr alle fleissig an den Tutorials arbeitet, so werkelt dieser Thread in meinem Hinterkopf.
Für unter anderem diesen Thread habe ich gestern - nachdem einer leicht peinlichen Datensicherheitspanne - sehr viele Klassen, die ich niemals für nötig erachtet hätte, in mein Repository eingecheckt.
So besitze ich jetzt z.B. XSD::Primitive::UInt, eine Klasse, die nicht anderes macht, als ein UInt zu wrappen und mit einem XSD::Type::String Parser und einer ToString()-Methode auszustatten, damit ich UInts problemlos per Template auf die Platte schreiben und wieder lesen kann.
Und damit die ganze Mühe nicht umsonst ist (ist sie sowieso nicht. , verdiene ich mir hiermit mal ein:
Push
Für unter anderem diesen Thread habe ich gestern - nachdem einer leicht peinlichen Datensicherheitspanne - sehr viele Klassen, die ich niemals für nötig erachtet hätte, in mein Repository eingecheckt.
So besitze ich jetzt z.B. XSD::Primitive::UInt, eine Klasse, die nicht anderes macht, als ein UInt zu wrappen und mit einem XSD::Type::String Parser und einer ToString()-Methode auszustatten, damit ich UInts problemlos per Template auf die Platte schreiben und wieder lesen kann.
Und damit die ganze Mühe nicht umsonst ist (ist sie sowieso nicht. , verdiene ich mir hiermit mal ein:
Push
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
- cloidnerux
- Moderator
- Beiträge: 3123
- Registriert: Fr Sep 26, 2008 4:37 pm
- Wohnort: Ram (Gibts wirklich)
Re: Ein String im String suchen.
Mhmm, hab auch immer mal wieder hieran gedacht und daran, das ich bisher noch nix gemacht habe^^
Hab im moment so viel anderes, was ich tun will und muss, was meistens nichts mit Programmieren zu tun hat.
Zudem habe ich mir auch noch vorgenommen, mindestens 5 Artikel zu schreiben^^
Mal sehen ob ich nachher Zeit und Kaffee finde^^.
Hab im moment so viel anderes, was ich tun will und muss, was meistens nichts mit Programmieren zu tun hat.
Zudem habe ich mir auch noch vorgenommen, mindestens 5 Artikel zu schreiben^^
Mal sehen ob ich nachher Zeit und Kaffee finde^^.
Redundanz macht wiederholen unnötig.
quod erat expectandum
quod erat expectandum
- Xin
- nur zu Besuch hier
- Beiträge: 8859
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Ein String im String suchen.
Ich mache auch zu viele Sachen parallel. Dann geht alles nur sehr langsam vorwärts, aber irgendwann gibt's dann den Clash, wo aufeinmal 5 Dinge gleichzeitig fertig werden, ich auf einmal nicht mehr mehr viel zu tun habe und ich den gleichen Fehler mache wie immer.... dank der vielen Zeit fange ich 5 neue Dinge an...cloidnerux hat geschrieben:Mhmm, hab auch immer mal wieder hieran gedacht und daran, das ich bisher noch nix gemacht habe^^
Hab im moment so viel anderes, was ich tun will und muss, was meistens nichts mit Programmieren zu tun hat.
Am 1. Juni 2008 begann für mich zwei Monate Urlaub... am 5. Juni registrierte ich die Domain 'proggen.org'...
*daumendrück*cloidnerux hat geschrieben:Zudem habe ich mir auch noch vorgenommen, mindestens 5 Artikel zu schreiben^^
Mal sehen ob ich nachher Zeit und Kaffee finde^^.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Re: Ein String im String suchen.
*ausgrab* ^^
Hab mich eben wieder mit dem Thema beschäftigt, weil ich schon ewig eine Idee im Kopf hatte. Und zwar verwende ich für meine Suche zeichenweises, rekursives Hashing.
Für die Implementierung verwende ich C++ ohne irgendwelche Zusatzbibliotheken. Kompiliert wird das ganze also einfach mit:
Hier eine Proof-of-Concept-Implementierung, die bestimmt noch optimierungsfähig ist:
Beispielaufruf mit der obigen Datei "main.cpp", wobei nach "argv" gesucht wird:
Das ganze geht natürlich auch mit Leerzeichen:
Als Ergebnis wird die Zeilennummer und der Text der Zeile ausgegeben, das Prinzip wäre aber leicht auch noch auf Zeichen innerhalb der Zeile verbesserbar. Das Löschen von Daten fehlt ebenfalls noch, sollte aber auch in linearem Aufwand möglich sein.
Vorteil: Linearer Suchaufwand (bezüglich des gesuchten Textes), unabhängig von der Länge des gesamten Textes
Nachteil: Hoher Speicherbedarf (ein vielfaches der Eingabe, abhängig von der Anzahl der Einheiten, in dieser Implementierung also Wörter); nicht-zusammenhängende Matches (z.B. "unsigned i" in "unsigned int i" zu finden) dürfte schwerer werden
Bei vielen Ergebnissen wird das zurückgeben der Vektoren in LetterEntry::find() aufwendig... kann ich das noch optimieren? Eigentlich bräuchte ich da ja nur eine flache Kopie, da ich die sowieso in einem neuen Vektor zusammenhänge. Kann ich das außer mit Zeiger auf private Objekte noch anders (eleganter) lösen?
Hab ich damit eigentlich das Rad neu erfunden? ^^ Gibts diesen Algorithmus schon unter einem bestimmten Namen? ^^
Für Fragen bzw. Optimierungs- und Implementierungs-Vorschläge bin ich natürlich offen
Hab mich eben wieder mit dem Thema beschäftigt, weil ich schon ewig eine Idee im Kopf hatte. Und zwar verwende ich für meine Suche zeichenweises, rekursives Hashing.
Für die Implementierung verwende ich C++ ohne irgendwelche Zusatzbibliotheken. Kompiliert wird das ganze also einfach mit:
Code: Alles auswählen
$ g++ -o find *.cpp -Wall -O2
Code: Alles auswählen
// main.cpp
#include <iostream>
#include <vector>
#include "HashData.h"
int main( int argc, char *argv[] )
{
if( argc < 3 )
{
std::cout << "./find [file] [text]" << std::endl;
return 1;
}
HashData data( argv[1] );
std::vector<int> results = data.find( argv[2] );
for( unsigned int i = 0; i < results.size(); i++ )
std::cout << ( results[i] + 1 ) << ": " << data.line( results[i] ) << std::endl;
return 0;
}
Code: Alles auswählen
// HashData.h
#ifndef HASHDATA_H
#define HASHDATA_H
#include <map>
#include <string>
#include "LetterEntry.h"
class HashData
{
public:
HashData( const char *const path );
std::vector<int> find( const char *const searchItem );
std::string line( const int index );
protected:
void organizeData();
private:
void loadFile( const char *const path );
std::vector<std::string> m_lines;
std::map<char, LetterEntry> m_data;
};
#endif
Code: Alles auswählen
// HashData.cpp
#include "HashData.h"
#include <fstream>
HashData::HashData( const char *const path )
{
loadFile( path );
organizeData();
}
std::vector<int> HashData::find( const char *const searchItem )
{
return m_data[searchItem[0]].find( searchItem );
}
void HashData::organizeData()
{
std::vector<std::string>::iterator it;
int i = 0;
for( it = m_lines.begin(); it != m_lines.end(); it++, i++ )
{
for( unsigned int j = 0; j < it->length(); j++ )
{
if( j == 0 || it->at( j - 1 ) == ' ' )
m_data[it->at( j )].add( it->c_str(), i );
}
}
}
std::string HashData::line( const int index )
{
return m_lines[index];
}
void HashData::loadFile( const char *const path )
{
std::ifstream is( path );
int c;
m_lines.push_back( std::string() );
while( is.good() )
{
c = is.get();
if( c == '\n' )
m_lines.push_back( std::string() );
else
m_lines.back().push_back( c );
}
is.close();
}
Code: Alles auswählen
// LetterEntry.h
#ifndef LETTERENTRY_H
#define LETTERENTRY_H
#include <map>
#include <vector>
class LetterEntry
{
public:
void add( const char *const text, const int lineIndex );
std::vector<int> find( const char *const searchItem );
private:
std::map<char, LetterEntry> m_data;
std::vector<int> m_lineIndexes;
};
#endif
Code: Alles auswählen
// LetterEntry.cpp
#include "LetterEntry.h"
void LetterEntry::add( const char *const text, const int lineIndex )
{
m_lineIndexes.push_back( lineIndex );
if( *( text + 1 ) != '\0' )
m_data[text[1]].add( text + 1, lineIndex );
}
std::vector<int> LetterEntry::find( const char *const searchItem )
{
std::vector<int> results( m_lineIndexes );
if( m_data.count( searchItem[1] ) > 0 )
{
std::vector<int> prev = m_data[searchItem[1]].find( searchItem + 1 );
results.insert( results.end(), prev.begin(), prev.end() );
}
return results;
}
Code: Alles auswählen
$ ./find main.cpp argv
6: int main( int argc, char *argv[] )
8: if( argc < 3 )
14: HashData data( argv[1] );
15: std::vector<int> results = data.find( argv[2] );
Code: Alles auswählen
$ ./find main.cpp "unsigned int"
16: for( unsigned int i = 0; i < results.size(); i++ )
Vorteil: Linearer Suchaufwand (bezüglich des gesuchten Textes), unabhängig von der Länge des gesamten Textes
Nachteil: Hoher Speicherbedarf (ein vielfaches der Eingabe, abhängig von der Anzahl der Einheiten, in dieser Implementierung also Wörter); nicht-zusammenhängende Matches (z.B. "unsigned i" in "unsigned int i" zu finden) dürfte schwerer werden
Bei vielen Ergebnissen wird das zurückgeben der Vektoren in LetterEntry::find() aufwendig... kann ich das noch optimieren? Eigentlich bräuchte ich da ja nur eine flache Kopie, da ich die sowieso in einem neuen Vektor zusammenhänge. Kann ich das außer mit Zeiger auf private Objekte noch anders (eleganter) lösen?
Hab ich damit eigentlich das Rad neu erfunden? ^^ Gibts diesen Algorithmus schon unter einem bestimmten Namen? ^^
Für Fragen bzw. Optimierungs- und Implementierungs-Vorschläge bin ich natürlich offen
- Xin
- nur zu Besuch hier
- Beiträge: 8859
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Ein String im String suchen.
Wir haben einen Kandidaten, leider ohne passendes Interface.
Interface: siehe hier.
Der Sommer geht, die Knobel-Zeit beginnt... wer möchte sich noch versuchen?
Interface: siehe hier.
Der Sommer geht, die Knobel-Zeit beginnt... wer möchte sich noch versuchen?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Re: Ein String im String suchen.
Na gut, nochmal mit passendem Interface ^^Xin hat geschrieben:Wir haben einen Kandidaten, leider ohne passendes Interface.
Interface: siehe hier.
Code: Alles auswählen
// LetterEntry.h
#ifndef LETTERENTRY_H
#define LETTERENTRY_H
#include <map>
#include <vector>
#include <string>
#include <cctype>
class LetterEntry
{
public:
void add( const char *const text, const char *const id );
const std::vector<std::string>& find( const char *const searchItem );
private:
std::map<char, LetterEntry> m_data;
std::vector<std::string> m_ids;
static std::vector<std::string> sm_empty;
};
#endif
Code: Alles auswählen
// LetterEntry.cpp
#include "LetterEntry.h"
std::vector<std::string> LetterEntry::sm_empty;
void LetterEntry::add( const char *const text, const char *const id )
{
m_ids.push_back( id );
if( *( text + 1 ) != '\0' && isprint( *( text + 1 ) ) )
m_data[text[1]].add( text + 1, id );
}
const std::vector<std::string>& LetterEntry::find( const char *const searchItem )
{
if( *( searchItem + 1 ) == '\0' )
return m_ids;
else if( m_data.count( searchItem[1] ) > 0 )
return m_data[searchItem[1]].find( searchItem + 1 );
else
return sm_empty;
}
Code: Alles auswählen
// HashSearch.h
#ifndef HASHSEARCH_H
#define HASHSEARCH_H
#include "SearchBase.h"
#include "LetterEntry.h"
#include <vector>
#include <string>
#include <map>
class HashSearch : public SearchBase
{
public:
HashSearch();
void addText( char const *id, char const *text );
void addPattern( char const *pattern );
void clearPatterns();
int seek( char const *filename );
private:
std::vector<std::string> m_patterns;
std::vector<std::string> m_ids;
std::map<char, LetterEntry> m_data;
int m_numIds;
};
#endif
Code: Alles auswählen
// HashSearch.cpp
#include "HashSearch.h"
#include <cstdio>
HashSearch::HashSearch()
{
m_numIds = 0;
}
void HashSearch::addText( char const *id, char const *text )
{
for( int i = 0; text[i] != '\0'; ++i )
{
if( i == 0 || isspace( text[i - 1] ) )
m_data[*( text + i )].add( text + i, id );
}
}
void HashSearch::addPattern( char const *pattern )
{
m_numIds++;
m_patterns.push_back( pattern );
}
void HashSearch::clearPatterns()
{
m_numIds = 0;
m_patterns.clear();
}
int HashSearch::seek( char const *filename )
{
std::map<std::string, int> idCount;
for( std::vector<std::string>::iterator stringIt = m_patterns.begin(); stringIt != m_patterns.end(); ++stringIt )
{
std::vector<std::string> results( m_data[stringIt->at( 0 )].find( stringIt->c_str() ) );
for( std::vector<std::string>::iterator resultIt = results.begin(); resultIt != results.end(); ++resultIt )
idCount[*resultIt]++;
}
FILE *f = fopen( filename, "w" );
if( f == NULL )
{
fprintf( stdout, "Error creating file\n" );
return -1;
}
for( std::map<std::string, int>::iterator mapIt = idCount.begin(); mapIt != idCount.end(); ++mapIt )
{
if( mapIt->second == m_numIds )
fprintf( f, "%s\n", mapIt->first.c_str() );
}
fclose( f );
return idCount.size();
}
Code: Alles auswählen
// SearchBase.h
#ifndef SEARCHBASE_H
#define SEARCHBASE_H
class SearchBase
{
public:
virtual void addText( char const *id, char const *text ) = 0;
virtual void addPattern( char const *pattern ) = 0;
virtual void clearPatterns() = 0;
virtual int seek( char const *filename ) = 0;
};
#endif
Ich hab die anderen Codes noch nicht angesehen und bin nicht sicher, ob mein doch relativ aufwendiges Hashing damit mithalten kann. Jedenfalls denke ich, dass meine Chancen mit der Länge der Texte und vor allem der Anzahl der Suchvorgänge steigen.
Eventuell reiche ich noch eine zweite Lösung ein ^^
- Xin
- nur zu Besuch hier
- Beiträge: 8859
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Ein String im String suchen.
Die Main brauche ich eigentlich auch gar nicht. ^^
Grundsätzilch finde ich es gut, den Quelltext lesen zu können, aber könntest Du bei der nächsten Version zusätzlich ein ZIP-Archiv dranhängen? ^^
Ich werd's morgen mal an die Suchmaschine hängen, meine konnte ich wieder kompilieren, aber hab wohl irgendwas kaputt gemacht.
Grundsätzilch finde ich es gut, den Quelltext lesen zu können, aber könntest Du bei der nächsten Version zusätzlich ein ZIP-Archiv dranhängen? ^^
Ich werd's morgen mal an die Suchmaschine hängen, meine konnte ich wieder kompilieren, aber hab wohl irgendwas kaputt gemacht.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
- fat-lobyte
- Beiträge: 1398
- Registriert: Sa Jul 05, 2008 12:23 pm
- Wohnort: ::1
- Kontaktdaten:
Re: Ein String im String suchen.
Ich hab da grad was in Petto, das eventuell interessant sein könnte. Please stand by.
Haters gonna hate, potatoes gonna potate.
- fat-lobyte
- Beiträge: 1398
- Registriert: Sa Jul 05, 2008 12:23 pm
- Wohnort: ::1
- Kontaktdaten:
Re: Ein String im String suchen.
So, hab jetzt auch mal was zum einreichen.
Gleichmal vornweg: die Grundidee für diesen Algorithmus ist *nicht* von mir.
Unser Bioinformatik-Prof hat uns gezwungen, die wichtigsten Papers zur identifikation homologien in Proteinsequenzen zu lesen. Er meinte zwar "Algorithmen braucht ihr nicht zu lernen", allerdings war ich ein bisschen Neugierig.
Die Grundidee habe ich von einem gewissen Herrn Lipman geklaut: http://www.ncbi.nlm.nih.gov/pubmed/2983426
Der Algorithmus braucht ziemlich viel permanenten Speicher, und zwar ein wenig mehr als textlänge*sizeof(char*). Dafür geht der Look-Up einigermaßen schnell.
Bitte kompilieren mit GCC >= 4.7 oder Clang >= 3.1.
Benötigte flags:
Vorgeschlagene Optimierungsflags:
Natürlich gibts wieder ein Git-Repository dazu: https://github.com/fat-lobyte/proggen_searchwords
ps.: Mit nicht allzuviel Aufwand kann man den Algorithmus so verändern, dass er auch nicht-perfekte Matches findet.
Gleichmal vornweg: die Grundidee für diesen Algorithmus ist *nicht* von mir.
Unser Bioinformatik-Prof hat uns gezwungen, die wichtigsten Papers zur identifikation homologien in Proteinsequenzen zu lesen. Er meinte zwar "Algorithmen braucht ihr nicht zu lernen", allerdings war ich ein bisschen Neugierig.
Die Grundidee habe ich von einem gewissen Herrn Lipman geklaut: http://www.ncbi.nlm.nih.gov/pubmed/2983426
Der Algorithmus braucht ziemlich viel permanenten Speicher, und zwar ein wenig mehr als textlänge*sizeof(char*). Dafür geht der Look-Up einigermaßen schnell.
Bitte kompilieren mit GCC >= 4.7 oder Clang >= 3.1.
Benötigte flags:
Code: Alles auswählen
-std=c++0x
Code: Alles auswählen
-O3 -DNDBEBUG -msse4.2 -fno-rtti -fno-exceptions
ps.: Mit nicht allzuviel Aufwand kann man den Algorithmus so verändern, dass er auch nicht-perfekte Matches findet.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Haters gonna hate, potatoes gonna potate.
- Xin
- nur zu Besuch hier
- Beiträge: 8859
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Ein String im String suchen.
Ich will zusehen, dass ich eure Lösungen heute abend mal in mein Projekt einbinden kann und die mal gegeneinander ausspielen lasse.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.