2013-05-16 10 views
5

Wie liest man eine Zeile als Bereich in D?Wie liest man einen String Zeichen für Zeichen als Bereich in D?

Ich weiß, es gibt Bereiche in D, aber ich frage mich einfach, wie man einfach über jedes Zeichen einer Zeichenfolge mit diesem Konzept iterieren?

Um zu zeigen, was ich nach der ähnlichen Code in Go ist:

for _, someChar := range someString { 
    // Do something 
} 
+1

http://ddili.org/ders/d.en/ranges.html – sigod

+0

@sigod, ja, sollte Alis Buch überprüft haben! Es ist definitiv die Ressource für das Lesen von D-Sachen im Moment. –

Antwort

12

Das hängt davon ab, ob Sie über Code-Einheiten oder Codepunkte iterieren möchten. Die Sprache selbst iteriert über Arrays von Array-Elementen und Strings sind Anordnungen von Codeeinheiten, wenn Sie also einfach foreach mit Typinferenz verwenden, dann mit

foreach(c; "La Verité") 
    writeln(c); 

den letzten beiden Zeichen Kauderwelsch wäre gedruckt, weil é a Codepunkt, der aus zwei UTF-8-Code-Einheiten besteht, und Sie drucken einzelne Code-Einheiten aus (da char eine UTF-8-Code-Einheit ist). Während, wenn Sie das tun

foreach(dchar c; "La Verité") 
    writeln(c); 

dann der Laufzeit wird die Codeeinheiten zu Codepunkten dekodieren und é wird als letztes Zeichen gedruckt werden. Aber nichts davon funktioniert wirklich auf Strings als Bereiche. foreach arbeitet nativ mit Arrays, ohne die Eingabebereichs-API zu verwenden. Doch für alle String-Typen, sieht der Bereich API wie

@property bool empty(); 
@property dchar front(); 
void popFront(); 

Es auf Strings als Bereiche dchar arbeitet - nicht ihren Code Einheitentyp. Dies vermeidet Probleme mit Funktionen wie std.algorithm.filter, die auf einzelnen Code-Einheiten arbeiten, da dies keinen Sinn ergeben würde. Der Umgang mit Codepunkten ist auch nicht 100% richtig, da Unicode sehr kompliziert wird in Bezug auf die Kombination von Codepunkten und Graphemen und so weiter, aber die Arbeit mit Codepunkten ist viel näher an der Korrektheit (und ich glaube, es wird an der Erweiterung gearbeitet) Unterstützung von Graphemen in der Standardbibliothek für die Fälle, in denen Sie dies benötigen und bereit sind, den Leistungshit zu zahlen). Also, API, um den Bereich mit für Saiten auf sie als Bereiche von dchar arbeiten weit mehr richtig, und wenn man etwas tut, wie

foreach(c; filter!"true"("La Verité")) 
    writeln(c); 

würden Sie Iterieren vorbei sein dchar und é würde richtig gedruckt.Der Nachteil all dessen ist natürlich die Tatsache, dass foreach on Strings standardmäßig auf der Ebene der Code-Einheit arbeitet, während die Range-API für Strings als Codepunkte auf ihnen arbeitet, so dass Sie beim Mischen von Array-Operationen und range-based vorsichtig sein müssen Operationen auf Strings. Deshalb werden string und wstring nicht als Random-Access-Bereiche betrachtet - nur bidirektionale Bereiche. Sie können in O (1) keinen wahlfreien Zugriff auf Codepunkte ausführen, wenn sie aus einer unterschiedlichen Anzahl von Codeeinheiten bestehen (wobei dstring ein Random-Access-Bereich ist, da bei UTF-32 jede Codeeinheit ein Codepunkt).

+0

Was passiert, wenn ich std.array importiere, das die benötigten Range-Funktionen auf UFCS-Ebene zur Verfügung stellt, wird die Iteration über einen String immer noch derselbe sein? – dav1d

+0

@ dav1d 'foreach' auf Array wird immer nur die Array-API verwenden. Bei Arrays müssen die bereichsbasierten Funktionen explizit verwendet werden. Und so nervend wie die Inkonsistenz mit foreach ist, hängt das Verhalten davon ab, ob std.array importiert wurde oder nicht, wäre sehr fehleranfällig, da das Hinzufügen oder Entfernen dieses Imports das Verhalten Ihres Codes je nach dem was drastisch verändern könnte es hat getan. –

+0

Ja, ich hatte wirklich gehofft, dass es den Code nicht ändern würde. Auf der anderen Seite erlaubt UFCS das Iterieren über Objekte, die die Schnittstelle opApply (könnte hier falsch sein) oder Bereich nicht implementieren. Danke für die Klarstellung. – dav1d

1
foreach(ch; str) 
    do_something(ch); 

Ein String ist ein InputRange. Ein InputRange implementiert drei Dinge:

  • leer; ist es leer?
  • Vorderseite; gib mir den nächsten Artikel.
  • popFront; Erhöhen Sie den Bereich, sonst kehrt Front gleich zurück.

foreach "versteht", wie man mit Bereichen arbeitet, so dass es "einfach funktioniert".

Aber ich spreche nicht Go, also bin ich mir nicht ganz sicher, ob wir die gleiche Sprache sprechen.

+0

Ja, natürlich, Ugh, ich weiß nicht, wie ich das hier vergessen könnte, habe es schon ein paar Mal benutzt, also sollte ich es wissen ... muss dem Mangel an Schlaf die Schuld geben letzte Nacht :) –

+0

Ich höre dich, Ich bin mir im Moment nicht ganz klar. – 0b1100110

+2

Achten Sie jedoch hier auf Typinferenz. Dieser Code iteriert über Code-Einheiten und nicht über Codepunkte. Daher ist es unwahrscheinlich, dass Unicode korrekt ausgeführt wird. –

Verwandte Themen