2010-09-23 8 views
5

Je veux diviser une chaîne en supprimant tous les champs nullÉclate une chaîne supprimant tous les champs null

Commande:

",1,2,,3,4,,".split(',') 

Résultat:

["", "1", "2", "", "3", "4", ""] 

attendu:

["1", "2", "3", "4"] 

Comment faire ça?


Modifier

Ok. Juste pour résumer toutes ces bonnes questions postées. Ce que je voulais, c'est que la méthode split (ou autre méthode) ne génère pas de chaînes vides. On dirait que ce n'est pas possible. Donc, la solution est un processus en deux étapes: séparer la chaîne comme d'habitude, puis supprimer les chaînes vides du tableau résultant.

La deuxième partie est exactement this question (et son duplicate)

donc j'utiliser

",1,2,,3,4,,".split(',').delete_if(&:empty?) 

La solution proposée par Nikita Rybak et par user229426 est d'utiliser la méthode de rejet. Selon docs rejeter renvoie un nouveau tableau. Alors que la méthode delete_if est plus efficace car je ne veux pas de copie. En utilisant select proposé par Mark Byers encore plus inefficace.

steenslag propose de remplacer des virgules avec l'espace, puis utilisez l'espace divisé par:

",1,2,,3,4,,".gsub(',', ' ').split(' ') 

En fait, the documentation dit que l'espace est en fait un espace blanc. Mais les résultats de "split (/ \ s /)" et "split ('')" ne sont pas les mêmes. Pourquoi ça? Mark Byers a proposé une autre solution - en utilisant simplement des expressions régulières. On dirait que c'est ce dont j'ai besoin. Mais cette solution implique que vous devez être maître de l'expression rationnelle. Mais c'est une excellente solution! Par exemple, si j'ai besoin des espaces pour être séparateurs, ainsi que tout symbole non alphanumérique je peux réécrire cela

",1,2, ,3 3,4 4 4,,".scan(/\w+[\s*\w*]*/) 

le résultat est:

["1", "2", "3 3", "4 4 4"] 

Mais encore une fois regexps sont très unintuitive et ils ont besoin une expérience.

Résumé

Je pense que scission de travailler avec comme si les espaces blancs étaient une virgule des espaces blancs ou même regexp. Je m'attends à ce qu'il ne produise pas de chaînes vides. Je pense que c'est un bug dans ruby ​​ou mon malentendu.

En fait une question de la communauté.

+0

Pas un expert rubis, mais semble http://stackoverflow.com/questions/3774509/eliminating-nil-lines est la même question plus ou moins, où vous mappez ma suppression sur la matrice, parler de timing. – Novikov

+0

Oui, c'est le cas. Merci – Vanuan

+0

Il est étrange pour moi aussi qu'une chaîne vide ('" "') soit renvoyée lorsque deux valeurs ne correspondent pas à l'expression rationnelle dans une ligne. – NotAnAmbiTurner

Répondre

10

Il y a une méthode reject dans Array:

",1,2,,3,4,,".split(',').reject { |s| s.empty? } 

Ou si vous préférez Symbol#to_proc:

",1,2,,3,4,,".split(',').reject(&:empty?) 
+0

J'ai trouvé une solution similaire: ", 1,2, 3,4" ,,. Split (','). Delete_if (&: vide?) – Vanuan

+0

@vanuan je voterais cette réponse si vous l'avez écrit @ nikita cela pourrait être simplifié en utilisant s.empty? plutôt que de comparer à la chaîne vide, et fait plus frais en appliquant le truC# to_proc trick vanuan utilisé dans son commentaire. c'est-à-dire réécrire le rejet comme .reject &: vide? –

+0

Encore plus court: ", 1,2,, 3,4 ,,". Split (','). Reject (&: vide?) –

1

Vous pouvez utiliser split suivie select:

",1,2,,3,4,,".split(',').select{|x|!x.empty?} 

Ou vous pouvez utiliser un regu LAR expression correspondant à ce que vous voulez garder au lieu de diviser le delimiter:

",1,2,,3,4,,".scan(/[^,]+/) 
0
",1,2,,3,4,,".split(/,/).reject(&:empty?) 

",1,2,,3,,,4,,".squeeze(",").sub(/^,*|,*$/,"").split(",") 
0

Chaîne # split (motif) se comporte comme désiré lorsque modèle est un espace unique (ruby-doc).

",1,2,,3,4,,".gsub(',', ' ').split(' ') 
+0

Hm ... Que faire si je veux que des espaces soient inclus dans les sous-chaînes? (", 1 2,, 3 4 ,,") Cela ne marchera pas – Vanuan

2

Espérant éclairer un peu ici:

Mais les résultats de "split (/ \ s /)" et « split (» «) » ne sont pas les mêmes. Pourquoi ça?

Si vous regardez la documentation pour cordes # Split, vous verrez que split avec '' est un cas particulier:

If pattern is a single space, str is split on whitespace, 
with leading whitespace and runs of contiguous whitespace characters ignored. 

Vous mentionnez aussi:

J'attends ne pas produire de chaînes vides. Je pense que c'est un bug dans ruby ​​ou mon malentendu.

Le problème se situe probablement entre le clavier et la chaise. ;-)

split va heureusement produire des chaînes vides comme il se doit, car il y a des moments où vous voudriez vraiment cette capacité, et il y a de nombreuses façons de contourner ce problème. Considérez si vous divisiez un fichier csv à partir d'un fichier Excel. N'importe où vous voyez ',,' serait une colonne vide, pas une colonne dont vous devriez vous débarrasser. Quoi qu'il en soit, vous avez vu un tas de solutions - et voici une autre qui pourrait vous montrer les choses que vous pouvez faire avec ruby ​​et split!

Il semble que vous voulez diviser les données entre multiples virgules, alors pourquoi ne pas essayer et voir ce qu'il se passe?

a = ",1,2,,3,4,,5,,,,6,,,".split(/,+/) 

Il est assez simple expression régulière: /, +/signifie une ou plusieurs virgules, donc nous séparons à ce sujet. Cela vous donne presque envie que vous voulez, sauf que vous voulez également ignorer le premier champ vide.Vous remarquerez que scission ignore le champ vide à la fin parce que (à partir de la documentation fendus String #):

If the limit parameter is omitted, trailing null fields are suppressed. 

Cela signifie donc que nous pouvons soit utiliser quelque chose qui va supprimer ce nul à l'avant du tableau ou il suffit de supprimer les virgules initiales. Nous pouvons utiliser gsub pour que:

a = ",1,2,,3,4,,5,,,,6,,,".gsub(/^,+/,'') 

Si vous imprimez que sur vous verrez que maintenant disparu notre « champ » de fuite vide. Nous pouvons donc les combiner en une seule ligne:

a = ",1,2,,3,4,,5,,,,6,,,".gsub(/^,+/,'').split(/,+/) 

Et vous avez une autre solution!

Et d'ailleurs, cela indique une autre possibilité, que nous pouvons simplement nettoyer notre chaîne entièrement avant de l'envoyer à scinder si nous voulons une simple division. Je vous laisse le soin de comprendre ce que celui-ci est en train de faire:

a = ",1,2,,3,4,,5,,,,6,,,".gsub(/,+/,',').gsub(/^,/,'').split(',') 

Il y a beaucoup de façons de faire les choses en rubis. S'il semble que ruby ​​ne fasse pas ce que vous voulez, alors jetez un coup d'œil sur les docs et réalisez que cela fonctionne probablement comme il le fait pour une raison (il y a beaucoup de gens qui seraient contrariés si split ne pouvait pas cracher des champs vides :)

Espérons que ça aide!

Questions connexes