RegEx pour supprimer le début répété de la ligne en utilisant TextWrangler

en Essayant de tourner

a: 1, 2, 3
a: a, b, v
b: 5, 6, 7
b: 10, 1543, 1345
b: e, fe, sdf
cd: asdf, asdfas dfasdfa,asdfasdfa,afdsfa sdf
e1: asdfas, dafasd, adsf, asdfasd
e1: 1, 3, 2
e1: 9, 8, 7, 6

en

a: 1, 2, 3
   a, b, v
b: 5, 6, 7
   10, 1543, 1345
   e, fe, sdf
cd: asdf, asdfas dfasdfa,asdfasdfa,afdsfa sdf
e1: asdfas, dafasd, adsf, asdfasd
    1, 3, 2
    9, 8, 7, 6

Donc, les lignes sont triées. Si des lignes consécutives commencent avec la même séquence de caractères jusqu'à / y compris un séparateur (ici les deux - points (et le blanc qui les suit)), seule la première instance doit être conservée-comme le reste de toutes les lignes. Il peut y avoir jusqu'à une douzaine (et demie) de lignes commençant par la séquence identique des caractères. L'entrée contient environ 4 500 les lignes...

essayé dans TextWrangler.

alors que le motif de recherche

^([[:alnum:]]+): (.+)r((:) (.+)r)*

correspond correctement, ni le remplacement

:trtr

ni

:trtr

me permet de me rapprocher de ce que je cherche.

le motif de recherche

^(.+): (.+)r((?<=:) (.+)r)*

est rejetée pour le lookbehind n'étant pas de longueur fixe. - Pas sûr, mais ça va dans la bonne direction.

en Regardant Comment fusionner les lignes qui commencent avec les mêmes éléments dans un fichier texte Je me demande s'il existe une solution élégante (par exemple: un modèle de recherche, un remplacement, lancer une seule fois).

d'un autre côté, je pourrais tout simplement ne pas être en mesure de trouver la bonne question pour chercher sur le net. Si vous le savez mieux, s'il vous plaît, dirigez-moi dans la bonne direction.

Gardant le reste des lignes alignées est, bien sûr, de sucre sur le gâteau...

je vous Remercie pour votre temps.

14
demandé sur Community 2014-08-14 04:40:15

6 réponses

comme solution de contournement pour la longueur variable lookbehind: PCRE permet des solutions de rechange de longueur variable

PCRE n'est pas entièrement Perl-compatible quand il s'agit de lookbehind. Alors que Perl nécessite des alternatives à l'intérieur de lookbehind pour avoir la même longueur, PCRE permet des alternatives de longueur variable.

une idée qui nécessite d'ajouter un tube pour chaque caractère de longueur du préfixe max:

(?<=(\w\w:)|(\w:)) (.*\n?)??

Et remplacer par \t. Voir test à regex101. Capturer à l'intérieur du lookbehind est important pour ne pas consommer / ne pas sauter une allumette. Même variable de motif par exemple .NET: (?<=(\w+:)) (.*\n?)?

  • (?<=(\w\w:)|(\w:)) les deux premiers groupes de capture à l'intérieur de lookbehind pour la capture de préfixe: Deux ou un caractères des mots suivi d'un côlon. \w est un abréviation[A-Za-z0-9_]

  • (.*\n?) troisième capture groupe pour des choses entre les préfixes. Newline en option pour obtenir le dernier match.

  • ?? remplacera optionnellement le même préfixe si dans la ligne suivante. Un seul des deux peut être défini: xor . De plus, l'espace après le colon correspondrait toujours - quel que soit le préfixe.


résumé: Espace après chaque préfixe est converti à l'onglet. Préfixe de la ligne suivante seulement si correspond actuel.

       De match et de remplacer les multiples espaces et de tabulations: (?<=(\w\w:) / (\w:)) [\t]+(.*\n?) \1?\2?

6
répondu Jonny 5 2015-08-04 06:14:58

le problème avec la substitution est le nombre incertain d'allumettes. Lorsque vous limitez ce nombre par exemple à 12, Vous pouvez utiliser un regex comme ceci:

^([^:]+): ([^\n]+[\n]*)(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?(: ([^\n]+[\n]*))?

avec ce remplacement:

\n:\t\t\t\t\t\t\t\t\t\t\t\t

explication: il ne contient essentiellement que deux sous-regexes

  • ^([^:]+): ([^\n]+[\n]*) = matchs sur la première ligne d'un groupe

  • (: ([^\n]+[\n]*))? = correspondances optionnelles sur les lignes consécutives, appartenant à le même groupe. Vous devez copier ce regex aussi souvent que nécessaire pour correspondre à toutes les lignes (i.e. dans ce cas 12x). ? (= optionnel) match ne vous donnera pas d'erreur s'il n'y a pas assez de matches pour toutes les substitutions.

  • \n au début de la substitution est nécessaire pour un problème de formatage

  • le résultat contiendra quelques lignes vides, mais j'en suis sûr, vous pouvez résoudre... ; -)

Démo 1

cependant, puisque je ne suis pas un fan de regexes surdimensionnés - et pour le cas où vous avez un plus grand nombre de correspondances potentielles - je préférerais une solution comme celle-ci:

DEMO 2

4
répondu Carsten Hagemann 2015-08-03 02:17:45

Le awk one-liner ci-dessous permettra de faire ce que vous voulez

awk -F: 'NR==1 {print } NR != 1 {if ( != prev) print ; else {for (i=0; i<=length(); ++i) printf " "; print ;}} {prev=}' < input_file.txt

(mettez le texte original dans input_file.txt)

je crois qu'il est possible d'écrire un beau code, mais il est temps d'aller au lit)

1
répondu John Smith 2015-08-02 03:34:06

j'ai essayé votre échantillon dans Bare Bones Software Inc.'s TextWrangler et je suis venu avec deux passes solution qui est limitée à n lignes consécutives, et il utilise un onglet au lieu d'essayer de magie correspondre à la longueur du préfixe. Notez également que la dernière ligne du fichier doit être une ligne vide (ajouter une nouvelle ligne après , 6 dans ton exemple)

Pour nos fins, je vous montre où n =4:

Find: ^([[:alnum:]]+\:)(.+\r)(?:(.+\r))?(.+)\r
Replace: \t\t\t\r

Vous pouvez ajouter une toute n en dupliquant un (?:(.+\r))?Find, et en ajoutant \t\n avant \rReplace où *n* est l'incrément après le dernier numéro avant que \r.

en remplaçant tout par ceci, vous pouvez suivre avec:

Find: ^\t+
Replace: \t

pour obtenir le résultat que vous voulez.

1
répondu dlamblin 2015-08-04 07:20:10

donc puisque vous voulez remplacer toutes les autres instances à part la première, je suppose que vous avez besoin de regex pour faire correspondre tout sauf la première pour que vous puissiez les remplacer. L'Expression Regular comme vous le savez ne peut pas moddifier ou modifier la chaîne d'origine, il suffit de retourner une correspondance spécifique, qui elle-même peut être utilisée pour spécifier des parties de la chaîne à moddifier.

Le meilleur des regex qui me vient en tête est /(\b[a-zA-Z0-9]+: )[^\n]+(?:\n|$)(?!)/g.

cela capturera chaque instance unique de xx: et match le dernier cas. Le seul problème avec ceci est qu'il correspondra toujours à la dernière instance même si c'est la seule.

ma conclusion est que je ne crois pas que vous puissiez faire tout cela avec regex. je me trompe peut-être, si quelqu'un peut trouver un débogueur regex en ligne qui supporte le lookbehind et le backreferencing, faites-le moi savoir et je verrai si je peux écrire une expression pour travailler. Personnellement, je n'ai pas pu trouver de débogueurs regex qui acceptent le backreferencing et le lookbehind. Dans mon exemple j'utilise lookahead à la place pour qu'il vérifie s'il y a des instances à l'avance, si c'est le cas, ignorez la correspondance courante (donc il ne sélectionne que la dernière instance).

Si tu voulais vraiment trouver un moyen d'automatiser cela pour le faire fonctionner, utilisez /(\b[a-zA-Z0-9]+: )/g pour faire correspondre chaque instance de xx:, stockez - les tous dans un tableau et s'il y a un duplicata, lancez le regex original sur celui spécifique pour continuer à le couper jusqu'à ce qu'il n'y ait plus de duplicata. Encore une fois, vous pouvez être en mesure de l'utiliser pour stocker des toutes les instances uniques et utiliser cela d'une manière ou d'une autre.

J'espère que cela vous aidera ou clarifiera votre problème, toutes mes excuses si ce n'est pas le cas.

0
répondu Flipybitz 2015-08-02 03:13:56

N'ont pas de Textwrangler pour tester, mais je test ça dans d'autres Regex Outil, il fonctionne bien, s'il vous plaît essayer:

(?<=(?:(?:.+\n)|^)(\w+?:).+\n)(?=\s)
-1
répondu Tim.Tang 2014-08-14 02:19:22