Comment «déposer» / supprimer des caractères devant une chaîne?

13

J'ai une chaîne que je voudrais manipuler. La chaîne est de H08W2345678savoir comment pourrais-je la manipuler pour que la sortie soit juste W2345678?

De même, si je voulais supprimer les 4 derniers caractères H08W2345678pour que je sache H08W234comment faire?

3kstc
la source
1
Il existe de nombreuses façons de manipuler les chaînes. Y a-t-il une raison spécifique pour utiliser sed?
don_crissti
@don_crissti Aucune raison, à part le manque d'expérience. Toutes les alternatives sont les bienvenues ...
3kstc
@don_crissti, l'histoire: à partir d'un fichier CSV filtré, je prends l'un des paramètres d'une ligne qui est H08W2345678et doit le manipuler. W2345678Cette valeur avec d'autres données sera mise dans un email envoyé. L'e-mailing sera effectué avec cron.
3kstc
@don_crissti awking. Je crée un tableau et modifie ensuite chacun des éléments du tableau (tous différemment - c'est-à-dire changer le timestaimp Epoch en secondes en une date, etc.)
3kstc
2
Vous pouvez faire des trucs comme ça avec awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Réponses:

19

Utiliser simplement bash (ou d' ksh93où vient cette syntaxe ou zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

echo "${string:0:-4}"
H08W234

Consultez le wiki Wooledge pour en savoir plus sur la manipulation des chaînes .

jasonwryan
la source
Cela nécessite bash 4.2 ou supérieur. Voir cette ancienne copie du Manuel de référence de Bash, Section 3.5.3, «Expansion des paramètres du shell» ou la réponse des poussins ici pour voir l'ancienne contrainte («la longueur doit être évaluée à un nombre supérieur ou égal à zéro»); … (Suite)
Scott
(Suite)… voir les modifications apportées à Bash (sur le wiki Bash Hackers) (faites défiler vers le bas de la section) ou les actualités bash de l'organisation Technology Infrastructure Services de la Case Western Reserve University (recherchez «ajouté à bash-4.2» puis faites défiler jusqu'à «q».) pour voir la révision. …………  "${string:0:${#string}-4}" Fonctionne dans la version bash 4.1 tant que la longueur $stringest d'au moins 4.
Scott
PS Cela étouffera également les chaînes comme abc-e, où, lorsque vous déposez les trois premiers caractères, vous vous retrouvez -e(car echo -ene fait pas ce que vous voulez).
Scott
8
$ echo "H08W2345678" | sed 's/^.\{3\}//'
W2345678

sed 's/^.\{3\}//'trouvera les trois premiers caractères par ^.\{3\}et remplacera par vide. Ici ^., correspondra à n'importe quel caractère au début de la chaîne ( ^indique le début de la chaîne) et \{3\}correspondra exactement au motif précédent 3 fois. Donc, ^.\{3\}correspondra aux trois premiers caractères.

$ echo "H08W2345678" | sed 's/.\{4\}$//'
H08W234

De même, sed 's/.\{4\}$//'remplacera les quatre derniers caractères par des blancs ( $indique la fin de la chaîne).

heemayl
la source
1
Pourriez-vous s'il vous plaît expliquer le 's/^.\{3\}//'et 's/.\{4\}$//'comme j'apprends encore sed, merci beaucoup
3kstc
@ 3kstc: Veuillez vérifier les modifications
heemayl
1
Pour quelques personnages, j'utiliser au ...lieu de .\{3\}car (pour moi) , il est plus facile à lire: sed -e 's/^...//' -e 's/....$//' ou en une seule expression avec alternance: sed -r 's/^...|....$//g'. S'il y avait plus de quelques caractères à supprimer, j'utiliserais l' /.\{17}\/expression à la place de /.............../.
Johnny
Cela se comportera mal si la chaîne est -eou -n. Bien sûr, le sens de « laisser tomber les 4 derniers caractères » est pas défini pour une chaîne plus courte de 4 caractères, mais, si quelqu'un voulait adapter ce laisser tomber le premier ou le dernier un caractère, il pourrait exploser.
Scott
2

Si vous avez un fichier dans lequel chaque ligne est une chaîne de onze caractères (ou autre) que vous souhaitez découper, sedc'est l'outil à utiliser. C'est bien pour manipuler une seule chaîne, mais c'est exagéré. Pour une seule chaîne, la réponse de Jason est probablement la meilleure, si vous avez accès à la version 4.2 ou supérieure de bash. Cependant, les syntaxes et semblent être uniques à bash (enfin, bash, ksh93, mksh et zsh) - je ne les vois pas dans The Open Group Base Specifications for Shell Command Language . Si vous êtes bloqué avec un shell compatible POSIX qui ne prend pas en charge l'expansion (extraction) de sous-chaîne, vous pouvez utiliser${parameter:offset}${parameter:offset:length}

$ printf "%s\n" "${string#???}"
W2345678

$ printf "%s\n" "${string%????}"
H08W234

utiliser printfau lieu de echopour se prémunir contre les chaînes comme abc-e, où, lorsque vous déposez les trois premiers caractères, vous vous retrouvez -e (et echo -ene faites pas ce que vous voulez).

Et, si vous n'utilisez pas du tout un shell de la famille Bourne (ou si vous utilisez un ancien système pré-POSIX), ceux-ci devraient toujours fonctionner:

$ expr " $string" : ' ...\(.*\)'
W2345678

$ expr " $string" : ' \(.*\)....'
H08W234

Le premier espace est d'éviter les problèmes avec les valeurs de supplémentaires $string qui sont réels expropérateurs (par exemple +,  /,  indexou match) ou d' options (par exemple  --, --helpou  --version).

Scott
la source
@ Stéphane Chazelas: (1) Merci de me rappeler un piège que je connaissais il y a environ 40 ans et que j'ai réussi à oublier. (2) J'ai toujours utilisé pour résoudre ce problème avec X; par exemple expr "X$string" : 'X...\(.*\)'. OMI, c'est plus facile à lire et à comprendre. Y a-t-il un problème avec cela, ou une raison de préférer un espace? (3) Aujourd'hui, j'ai appris que cela expr + "$string" : '...\(.*\)'fonctionne maintenant. Je ne me souviens pas de cela il y a 40 ans; est-il suffisamment utilisé pour être recommandé en toute sécurité? (4) Vous avez manqué une note sur la réponse de jasonwryan et une pioche sur la réponse de heemayl.
Scott
AFAIK, qui expr +est uniquement GNU (ne fonctionnera pas sur Solaris ni FreeBSD AFAICS). J'utilise l'espace au lieu de x car il est moins probable que certaines exprimplémentations aient des opérateurs qui commencent par l'espace qu'avec xet aussi parce qu'il est moins probable qu'il y ait des éléments d'assemblage qui commencent par l'espace qu'avec x. Mais je me rends compte que ce n'est probablement pas un bon choix pour expr " $a" "<" " $b"la comparaison de chaînes car certaines implémentations finissent par faire une comparaison numérique quand $a/ $bressemblent à des nombres. Peut expr "@@$a"...- être ou expr "x $a"pourrait être plus sûr.
Stéphane Chazelas
0

Avec:

string="H08W2345678"

Faire correspondre 3 ou 4 caractères semble simple (pour la plupart des shells):

$ printf '%s\t%s\n' "${string#???}" "${string%????}"
W2345678      H08W234

Pour les plus anciens shells (comme le shell Bourne), utilisez:

$ string=H08W2345678

$ expr " ${string}" : " ...\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\)...." '
H08W234

Si un nombre de caractères est nécessaire, utilisez:

$ expr " ${string}" : " .\{3\}\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\).\{4\}" '
H08W234

Bien sûr, ces expressions régulières fonctionnent également avec sed, awk et bash 3.0+:

$ echo "$string" | sed 's/^.\{3\}//'
W2345678

$ echo "$string" | sed 's/.\{4\}$//'
H08W234

$ echo "$string" | awk '{sub(/^.{3}/,"")}1'
W2345678

$ echo "$string" | awk '{sub(/.{4}$/,"")}1'
H08W234

$ r='^.{3}(.*)$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
W2345678

$ r='^(.*).{4}$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
H08W234
Isaac
la source
-1

Comment «déposer» / supprimer des caractères devant une chaîne?

J'ai une chaîne que je voudrais manipuler. La chaîne est H08W2345678 comment pourrais-je la manipuler pour que la sortie soit juste W2345678?

echo "H08W2345678" | cut -c 4-
aexl
la source
Cela ne répond qu'à la moitié de la question.
Kusalananda
Je crois que votre downvote est injuste. Cette moitié répond à la question que je me posais lorsque j'ai recherché sur google les premiers caractères et cette page est apparue dans les résultats de recherche. De plus, ce titre de page ne couvre que la moitié exacte de la question. Je suis revenu et j'ai contribué lorsque j'ai trouvé la solution que j'aimais - je pense que ce travail cutest beaucoup plus élégant que tout ce qui est sur cette page.
aexl