Je fais quelque chose où j'ai réalisé que je voulais compter le nombre de /
s que je pouvais trouver dans une chaîne, puis cela m'a frappé, qu'il y avait plusieurs façons de le faire, mais je ne pouvais pas décider quel était le meilleur (ou le plus facile) .
En ce moment, je vais avec quelque chose comme:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
Mais je n'aime pas ça du tout, des preneurs?
Je ne veux pas vraiment creuser RegEx
pour ça, n'est-ce pas ?
Je sais que ma chaîne aura le terme que je recherche, vous pouvez donc supposer que ...
Bien sûr, pour les chaînes dont la longueur> 1 ,
string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;
LEN(ColumnToCheck) - LEN(REPLACE(ColumnToCheck,"N",""))
.Réponses:
Si vous utilisez .NET 3.5, vous pouvez le faire dans une seule ligne avec LINQ:
Si vous ne souhaitez pas utiliser LINQ, vous pouvez le faire avec:
Vous pourriez être surpris d'apprendre que votre technique d'origine semble être environ 30% plus rapide que l'une ou l'autre! Je viens de faire un benchmark rapide avec "/ once / upon / a / time /" et les résultats sont les suivants:
(Les temps sont pour 50 000 000 itérations, il est donc peu probable que vous remarquiez beaucoup de différence dans le monde réel.)
la source
f == '\'
concerne les caractères dans une chaîne, pas les chaînes dans une chaîneDoit être plus rapide que le
source.Replace()
par lui-même.la source
la source
RegexOptions.IgnoreCase
.Regex.Escape(...)
ainsinew System.Text.RegularExpressions.Regex(needle).Matches(haystack).Count;
Si vous voulez pouvoir rechercher des chaînes entières, et pas seulement des caractères:
Lire "pour chaque caractère de la chaîne, prenez le reste de la chaîne à partir de ce caractère comme une sous-chaîne; comptez-le s'il commence par la chaîne cible".
la source
J'ai fait quelques recherches et découvert que la solution de Richard Watson est la plus rapide dans la plupart des cas. C'est le tableau avec les résultats de chaque solution dans le post (sauf ceux qui utilisent Regex car il lève des exceptions lors de l'analyse de la chaîne comme "test {test")
Vous pouvez voir qu'en cas de recherche du nombre d'occurrences de sous-chaînes courtes (1-5 caractères) dans une chaîne courte (10-50 caractères), l'algorithme original est préféré.
De plus, pour la sous-chaîne multicaractères, vous devez utiliser le code suivant (basé sur la solution de Richard Watson )
source
Regex.Escape(needle)
source="aaa" substring="aa"
je m'attendais à en récupérer 2, pas 1. Pour "corriger" cela,n += substring.Length
n++
overlapped
drapeau pour répondre à votre cas comme ceci:overlapped=True;.... if(overlapped) {++n;} else {n += substring.Length;}
LINQ fonctionne sur toutes les collections, et puisque les chaînes ne sont qu'une collection de caractères, que diriez-vous de ce joli petit one-liner:
Assurez-vous que vous avez
using System.Linq;
en haut de votre fichier de code, tout comme.Count
une méthode d'extension de cet espace de noms.source
int
les lettres résident toutes dans les clés de la maison, maisvar
pas. euh .. attendez, j'utilise DvorakSur mon ordinateur, c'est environ 2 secondes plus rapide que la solution pour tous les caractères pour 50 millions d'itérations.
Révision 2013:
Remplacez la chaîne par un char [] et parcourez-le. Réduit encore une ou deux secondes le temps total pour les itérations de 50 m!
C'est encore plus rapide:
Pour faire bonne mesure, l'itération de la fin du tableau à 0 semble être la plus rapide, d'environ 5%.
Je me demandais pourquoi cela pouvait être et parcourait Google (je me souviens de quelque chose à propos de l'itération inverse étant plus rapide), et je suis tombé sur cette question SO qui utilise déjà la technique de la chaîne à char [] de manière agaçante. Je pense que l'astuce d'inversion est nouvelle dans ce contexte, cependant.
Quel est le moyen le plus rapide pour parcourir les caractères individuels d'une chaîne en C #?
source
source.IndexOf('/', n + 1)
et perdre len++
et les crochets du moment :) En outre, mettez une variable à lastring word = "/"
place du caractère.la source
Ces deux ne fonctionnent que pour les termes de recherche à un seul caractère ...
peut se révéler meilleur pour les aiguilles plus longues ...
Mais il doit y avoir une manière plus élégante. :)
la source
Éditer:
la source
source.Split(new[]{"//"}, StringSplitOptions.None).Count - 1
pour les séparateurs multi-caractères.En C #, un joli compteur String SubString est ce gars incroyablement délicat:
la source
la source
stringToMatch
besoins qui s'échappent, pas leinput
.Parce que la solution d'origine était la plus rapide pour les caractères, je suppose que ce sera également le cas pour les chaînes. Voici donc ma contribution.
Pour le contexte: je cherchais des mots comme «échoué» et «réussi» dans un fichier journal.
Gr, Ben
la source
la source
Pour tous ceux qui souhaitent une méthode d'extension de chaîne prête à l'emploi,
voici ce que j'utilise qui était basé sur la meilleure des réponses postées:
la source
la source
Je pense que la façon la plus simple de le faire est d'utiliser les expressions régulières. De cette façon, vous pouvez obtenir le même nombre de divisions que vous pourriez utiliser avec myVar.Split ('x') mais dans un paramètre à plusieurs caractères.
la source
Cela comptera chaque fois que le programme trouvera "/ s" exactement (sensible à la casse) et le nombre d'occurrences de ceci sera stocké dans la variable "occurrences"
la source
Je sentais que nous manquions de certains types de comptage de sous-chaînes, comme les comparaisons d'octets à octets dangereuses. J'ai rassemblé la méthode de l'affiche originale et toutes les méthodes auxquelles je pouvais penser.
Ce sont les extensions de chaîne que j'ai faites.
Suivi du code de test ...
Résultats: CSX correspond à CountSubstrX et CCX correspond à CountCharX. "chr" recherche une chaîne pour '_', "et" recherche une chaîne pour "et", et "mlw" recherche une chaîne pour "muchlongerword"
Et enfin, j'avais un fichier de 3,6 millions de caractères. C'était "derp adfderdserp dfaerpderp deasderp" répété 100 000 fois. J'ai recherché "derp" dans le fichier avec les méthodes ci-dessus 100 fois ces résultats.
Donc, ma 4ème méthode est définitivement la gagnante, mais, de façon réaliste, si un fichier de 3,6 millions de caractères 100 fois ne prend que 1586 ms dans le pire des cas, tout cela est assez négligeable.
Soit dit en passant, j'ai également recherché le caractère «d» dans le fichier de 3,6 millions de caractères avec 100 fois les méthodes CountSubstr et CountChar. Résultats...
La méthode des affiches originales est très mauvaise pour les aiguilles à caractère unique dans une grande botte de foin selon cela.
Remarque: Toutes les valeurs ont été mises à jour pour publier la sortie de la version. J'ai accidentellement oublié de miser sur le mode Release lors de ma première publication. Certaines de mes déclarations ont été modifiées.
la source
Une fonction générique pour les occurrences de chaînes:
la source
Une variation de la réponse de Richard Watson, légèrement plus rapide avec une amélioration de l'efficacité plus le caractère se produit dans la chaîne et moins de code!
Bien que je doive dire, sans tester intensivement chaque scénario, j'ai vu une amélioration de vitesse très significative en utilisant:
la source
Nécessaire de faire quelque chose de similaire pour tester les instructions conditionnelles à partir d'une chaîne.
Remplacé ce que je cherchais par un seul caractère et compté les instances du seul caractère.
Évidemment, le caractère unique que vous utilisez devra être vérifié pour ne pas exister dans la chaîne avant que cela ne se produise afin d'éviter des décomptes incorrects.
la source
Chaîne en chaîne:
Trouvez "etc" dans ".. JD JD JD JD etc. et etc. JDJDJDJDJDJDJDJD et etc."
Vérifiez les performances avant de jeter celui-ci comme non sain / maladroit ...
la source
Ma prise initiale m'a donné quelque chose comme:
L'aiguille dans une approche de meule de foin utilisant le remplacement et la division donne 21+ secondes alors que cela prend environ 15,2.
Modifier après avoir ajouté un peu qui ajouterait
substring.Length - 1
au charIndex (comme il se doit), c'est à 11,6 secondes.Edit 2: J'ai utilisé une chaîne qui avait 26 chaînes de deux caractères, voici les temps mis à jour pour les mêmes exemples de textes:
Aiguille dans une botte de foin (version OP): 7,8 secondes
Mécanisme suggéré: 4,6 secondes.
Edit 3: Ajout de la casse de coin à un seul caractère, il est passé à 1,2 seconde.
Edit 4: Pour le contexte: 50 millions d'itérations ont été utilisées.
la source
Je pensais que je jetterais ma méthode d'extension dans le ring (voir les commentaires pour plus d'informations). Je n'ai pas fait de benchmarking formel, mais je pense que cela doit être très rapide pour la plupart des scénarios.
EDIT: OK - donc cette question SO m'a amené à me demander comment les performances de notre implémentation actuelle se comparent à certaines des solutions présentées ici. J'ai décidé de faire un petit benchmark et j'ai trouvé que notre solution était très en ligne avec les performances de la solution fournie par Richard Watson jusqu'à ce que vous fassiez une recherche agressive avec de grandes chaînes (100 Kb +), de grandes sous-chaînes (32 Kb + ) et de nombreuses répétitions intégrées (10K +). À ce stade, notre solution était environ 2X à 4X plus lente. Compte tenu de cela et du fait que nous aimons vraiment la solution présentée par Richard Watson, nous avons refactorisé notre solution en conséquence. Je voulais juste mettre cela à la disposition de tous ceux qui pourraient en bénéficier.
Notre solution originale:
Et voici notre solution révisée:
la source
la source
Il vérifie simplement chaque caractère de la chaîne, si le caractère est le caractère que vous recherchez, ajoutez-en un à compter.
la source
Si vous consultez cette page Web , 15 façons différentes de le faire sont évaluées, y compris en utilisant des boucles parallèles.
Le moyen le plus rapide semble utiliser soit une seule boucle for threadée (si vous avez la version .Net <4.0) ou une boucle parallel.for (si vous utilisez .Net> 4.0 avec des milliers de vérifications).
En supposant que "ss" est votre chaîne de recherche, "ch" est votre tableau de caractères (si vous avez plus d'un caractère que vous recherchez), voici l'essentiel du code qui avait le temps d'exécution le plus rapide en un seul thread:
Le code source de référence est également fourni afin que vous puissiez exécuter vos propres tests.
la source
C'est pour compter l'occurrence du personnage. Pour cet exemple, la sortie sera "a4b4j3"
la source
Pour le cas d'un délimiteur de chaîne (pas pour le cas char, comme le dit le sujet):
string source = "@@@ once @@@ upon @@@ a @@@ time @@@";
int count = source.Split (new [] {"@@@"}, StringSplitOptions.RemoveEmptyEntries) .Length - 1;
Le délimiteur naturel de la valeur d'origine de l'affiche ("/ once / sur / a / heure /") est un caractère '/' et les réponses expliquent l'option source.Split (char []) si ...
la source
using System.Linq;
int CountOf => "A :: BC :: D" .Split ("::"). Longueur - 1;
la source