Stimmt. Nur, da sie nicht intrinsisch in der Sprache eingebaut sind (wie String-Formatting), sondern man eine separate Klasse braucht, seh ich sie eigentlich nicht als direkten Vergleich zu "blah $blubb xyz", welches eben keine zusätzlichen Sprachelemente benötigt (auch wenn es von der Syntax her ähnlich ist, aber das krieg ich mit String-Formatting und dicts auch hin dass es so ähnlich aussieht).Doch, seit PEP 292 (= Python 2.4) hat Python etwas vergleichbares, die Template-Strings.
Python-Spickzettel für PHP-Entwickler
-
- User
- Beiträge: 670
- Registriert: Sonntag 15. Januar 2006, 18:42
- Wohnort: Celle
- Kontaktdaten:
--- Heiko.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Okay, dann versuch ichs noch damit:
Auch nicht ganz vergleichbar, aber immerhin in der Sprache eingebaut.
Code: Alles auswählen
value = 10
print 'Value %(value)s' % locals()
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ein Python-C Spickzettel ist nicht so einfach, weil C nicht über so "fortgeschrittene" Datentypen verfügt, wie Python oder sogar PHP.Python Master 47 hat geschrieben:Ich fände sowas für Pythn-C/C++ sehr gut!Mr_Snede hat geschrieben: OT:
wäre lustig sowas auch für Python - Ruby bzw Python - Perl zu haben.
C Felder kennen zum Beispiel ihre Länge nicht, die muss man sich entweder gesondert merken, oder eine Endmarkierung benutzen, die nicht regulär im Feld vorkommen darf. Bei Zeichenketten, die eigentlich nur Felder vom Typ `char` sind, ist das zum Beispiel das Nullbyte.
Während ein Feld anlegen noch einfach ist...
Code: Alles auswählen
char *array[] = {"foo", "bar", "frobnitz"};
Code: Alles auswählen
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
typedef int bool;
typedef int (*cmp_func)(const void *a, const void *b);
bool in_array(const void **array,
const unsigned int array_size,
const void *needle,
const cmp_func cmp)
{
unsigned int i;
for (i=0; i < array_size; ++i) {
if (cmp(needle, array[i]) == 0) {
return TRUE;
}
}
return FALSE;
}
Code: Alles auswählen
if (in_array(array, 3, "bar", strcmp)) {
puts("Ist drin");
}
`join()` ist dann wegen der Speicherverwaltung, um die man sich bei C selbst kümmern muss, noch umfangreicher. Für das Ergebnis muss man soviel Speicher anfordern, das alle Zeichenketten plus den Seperatoren hineinpassen, also muss man in einem ersten Schritt ersteinmal die Längen der einzelnen Zeichenketten herausfinden. Dann kann man den Speicher anfordern und die einzelnen Zeichenketten und Seperatoren dort hin kopieren.
Code: Alles auswählen
char* str_join(const char *separator,
const char **strings,
const unsigned int array_size)
{
unsigned int i, separator_length, *lengths;
unsigned int new_size;
char *result, *ptr;
separator_length = strlen(separator);
new_size = 1 + (array_size - 1) * separator_length;
lengths = malloc(array_size * sizeof(unsigned int));
for (i=0; i < array_size; ++i) {
lengths[i] = strlen(strings[i]);
new_size += lengths[i];
}
result = malloc(new_size * sizeof(char));
ptr = result;
for (i=0; i < array_size; ++i) {
memcpy(ptr, strings[i], lengths[i]);
ptr += lengths[i];
if (i != array_size - 1) {
memcpy(ptr, separator, separator_length);
ptr += separator_length;
}
}
*ptr = '\0';
free(lengths);
return result;
}
Anwendung der Funktion:
Code: Alles auswählen
char *str;
str = str_join("-", array, 3);
puts(str);
free(str);
Code: Alles auswählen
char** str_split(const char *string,
const char *separator,
unsigned int *result_size)
{
unsigned int i, str_length, separator_length;
char **result, *str, *start, *end;
str = strdup(string);
str_length = strlen(str);
separator_length = strlen(separator);
i = 0;
result = malloc((str_length / 2) * sizeof(char**));
start = str;
while ((end = strstr(start, separator))) {
*end = '\0';
result[i++] = strdup(start);
start = end + separator_length;
}
result[i++] = strdup(start);
free(str);
result = realloc(result, i * sizeof(char**));
*result_size = i;
return result;
}
Code: Alles auswählen
char **strings;
unsigned int i, size;
strings = str_split("foo<->bar<->frobnitz", "<->", &size);
for (i=0; i < size; ++i) {
puts(strings[i]);
/* free(strings[i]); */
}
/* free(strings); */
Ob das in C++ so viel einfacher wird, wage ich zu bezweifeln. Klar man hat Objekte, aber mit Objekten und Templates bekommt man auch sehr viel mehr Komplexität mit der man sich herumschlagen muss.
Einer Python-Liste am nächsten kommt wohl der `vector` in C++:
Wenn man das temporäre `char`-Feld nicht haben möchte, dann könnte man alternativ auch die drei Zeichenketten einzeln an den `vector` anhängen:
Schon wenn man den ``in`` Operator aus Python als Funktion für einen beliebigen Container aus der STL von C++ implementieren möchte, wird man mit Templates konfrontiert:
Man kann `find()` natürlich auch direkt in ``if``-Abfragen benutzen. Den Fall habe ich im folgenden auskommentiert:
Die Länge eines Containers kann man natürlich sehr schön ermitteln, da die Objekte eine entsprechende Methode besitzen:
`join()` und `split()` muss man sich aber selbst schreiben.
Zu benutzen sind die beiden so:
Ob das nun einfacher ist als bei C!? Ich finde C++ auf jeden Fall hässlicher. Insbesondere Fehlermeldungen, die mit Templates zusammenhängen und die Komplexität von Templates im allgemeinen. Ein verkorkster Versuch das starre Typsystem aufzubrechen, IMHO.
Zu den Template-Fehlermeldungen hier ein nettes Beispiel, welches mir beim Schreiben der Beispiele untergekommen ist:
Da weiss man doch sofort was man falsch gemacht hat, oder!?
Nochmal zum PHP-Python Spickzettel: Bei dem `substr()` Beispiel sollte auf jeden Fall ein Satz erklären, dass die beiden Argumente bei PHP Start und Länge, bei Python aber Start und Ende darstellen. Aus den angegebenen Beispielen wird das nämlich nicht unbedingt klar.
Einer Python-Liste am nächsten kommt wohl der `vector` in C++:
Code: Alles auswählen
char *tmp[] = {"foo", "bar", "frobnitz"};
vector<string> array(&tmp[0], &tmp[3]);
Code: Alles auswählen
vector<string> array;
array.push_back("foo");
array.push_back("bar");
array.push_back("frobnitz");
Code: Alles auswählen
template<class Iterable, class T>
bool contains(Iterable iterable, const T& element)
{
return find(iterable.begin(), iterable.end(), element) != iterable.end();
}
Code: Alles auswählen
// if (find(array.begin(), array.end(), "bar") != array.end()) {
if (contains(array, "bar")) {
cout << "Ist drin" << endl;
}
Code: Alles auswählen
cout << array.size() << endl;
Code: Alles auswählen
template<class Iter>
string join(const string& separator, const Iter& begin, const Iter& end)
{
string result;
for (Iter i=begin; i != end; ++i) {
result += *i;
if (i != (end - 1)) {
result += separator;
}
}
return result;
}
template<class StringContainer>
StringContainer split(const string& str, const string& separator)
{
StringContainer result;
size_t start, end;
start = 0;
while ((end = str.find(separator, start)) != str.npos) {
result.push_back(str.substr(start, end - start));
start = end + separator.length();
}
result.push_back(str.substr(start));
return result;
}
Code: Alles auswählen
cout << join("-", array.begin(), array.end()) << endl;
list<string> splitted = split<list<string> >("foo<->bar<->frobnitz", "<->");
Zu den Template-Fehlermeldungen hier ein nettes Beispiel, welches mir beim Schreiben der Beispiele untergekommen ist:
Code: Alles auswählen
test.cpp: In function `int main()':
test.cpp:55: error: could not convert `std::find [with _InputIterator =
__gnu_cxx::__normal_iterator<std::string*, std::vector<std::string,
std::allocator<std::string> > >, _Tp = char[4]]((&array)->std::vector<_Tp,
_Alloc>::begin [with _Tp = std::string, _Alloc = std::allocator<std::string>](),
(&array)->std::vector<_Tp, _Alloc>::end [with _Tp = std::string, _Alloc =
std::allocator<std::string>](), ((const char (&)[4])"bar"))' to `bool'
Nochmal zum PHP-Python Spickzettel: Bei dem `substr()` Beispiel sollte auf jeden Fall ein Satz erklären, dass die beiden Argumente bei PHP Start und Länge, bei Python aber Start und Ende darstellen. Aus den angegebenen Beispielen wird das nämlich nicht unbedingt klar.
-
- User
- Beiträge: 5
- Registriert: Montag 10. April 2006, 17:29
- Wohnort: Kirchen (Sieg)
- Kontaktdaten:
Danke erst mal für die Anregungen. Ich habe das PDF in der Version 2.0 zwischenzeitlich veröffentlicht und während meines Urlaubs sind einige positive Reaktionen eingetrudelt.
Den Hinweis zu substr() nehme ich auf jeden Fall noch auf, beim Rest sehe ich z.Zt. die Möglichkeit nicht. Sollte ich genug Material für eine Doppelseite zusammen haben, kommen natürlich alle gewünschten Ergänzungen rein.
Gruß, Marcel
Den Hinweis zu substr() nehme ich auf jeden Fall noch auf, beim Rest sehe ich z.Zt. die Möglichkeit nicht. Sollte ich genug Material für eine Doppelseite zusammen haben, kommen natürlich alle gewünschten Ergänzungen rein.
Gruß, Marcel