staging.inyokaproject.org

Text in Spalte ersetzen

Status: Ungelöst | Ubuntu-Version: Ubuntu 18.04 (Bionic Beaver)
Antworten |

giphy86

Anmeldungsdatum:
21. März 2018

Beiträge: 27

Hallo zusammmen , ich würde gerne mit diesem Script das zEICHEN IN Column 23 durch einen leeres Feld ersetzen wenn in dem Feld ein oder 2 Zahlen drinnenstehen.
Das Script macht dies auch. Allerdings hab ich ein Problem wenn der Inhalt von Spalte 23 auch in Spalte 1-22 vorkommt, werden diese Zeichen auch auf leer gesetzt.
Gibt es eine einfache Möglichkeit über sed oder awk den Change lediglich auf Spalte 23 zu begrenzen???

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash

while read i
do
if [[ $(echo $i | awk -F "|" '{print $23}' | wc -L ) =  "1" ]] || [[ $(echo $i | awk -F "|" '{print $23}' | wc -L ) =  "2" ]]
then
CHANGE==$(echo $i | awk -F "|" '{print $23}')
echo $i | sed 's/|'${change}'|/||' >> dpetest.txt
echo $i
else
echo $i >> dpetest.txt
fi
done < dpepre.txt

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@giphy86: Ich würde da deutlich mehr gleich in AWK lösen. Alleine die beiden ||-Verknüpften Tests könnte man in einem AWK-Aufruf und ohne wc lösen. Und Spalte 23 hast Du in AWK ja auch und kannst sie dort auch einfach durch etwas anderes ersetzen. Letztlich kann man das gesamte Skript leichter und einfacher in AWK ausdrücken.

Bei read möchtest Du übrigens in der Regel die Option -r verwenden.

Edit: Zeig doch bitte tatsächlichen Code und nicht etwas was so ähnlich aussieht. Das was Du zeigst hast Du offensichtlich nie ausprobiert. Eine sinnvolle Einrückung wäre auch nett dem Leser gegenüber. ☺

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

Auch Beispieldaten sind immer ganz hilfreich, wie sieht es vor der Bearbeitung aus, wie soll es danach aussehen, und was macht Dein Programm stattdessen daraus.

giphy86

(Themenstarter)

Anmeldungsdatum:
21. März 2018

Beiträge: 27

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
while read -r i
do
        if [[ $( echo $i | awk -F "|" '{print $23}' | wc -L ) ==  "1" ]] || [[ $( echo $i | awk -F "|" '{print $23}' | wc -L ) ==  "2" ]]
        then
                echo $i >> dpetest.txt
                CHANGE=$(echo $i | awk -F "|" '{print $23}')
                echo $i | sed 's/|'${CHANGE}'|/||/g' >> dpetest.txt
        else
                echo $i >> dpetest.txt
        fi
done < dpepre.txt

Input dpetest.txt

1
2
3
4
5
6
7
JFGDOI000000|12|12|20180328|707|850|190|0||0|85058838|0|||0||||||1||12||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||

Output soll so aussehen, Markiertes Feld soll leer sein

1
2
3
4
5
6
7
8
JFGDOI000000|12|12|20180328|707|850|190|0||0|85058838|0|||0||||||1||[mark]hier ersetzen[/mark]||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||

Er soll praktisch nur die 12 in Zeile 23 löschen

Moderiert von Vej:

Beitrag aus Spamfilter geholt.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

In Java sähe das so aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class Main {

    private static final int COLUMN_INDEX = 22;

    private Main() {}

    private static String replace(String line) {
        final String[] row = line.split("\\|");
        final int length = row[COLUMN_INDEX].length();
        if (length > 0 && length < 3) row[COLUMN_INDEX] = "";
        return String.join("|", row);
    }

    public static void main(String... args) throws IOException {
        Files.lines(Paths.get(args[0])).map(Main::replace).forEach(System.out::println);
    }
}

☺

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

giphy86 schrieb:

Er soll praktisch nur die 12 in Zeile 23 löschen

Die Spalte.

Mir war so, als ob sie gelöscht werden soll, wenn weniger als 3 Zeichen lang:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
while read line
do
   vorne=$(echo $line | cut -d"|" -f 1-22) 
   kritisch=$(echo $line | cut -d"|" -f 23)
   rest=$(echo $line | cut -d"|" -f 24- )
   if (( ${#kritisch} < 3 )) 
   then 
       echo $vorne"kritisch"$rest
   else
       echo $vorne$kritisch$rest 
   fi
done < dpetest.txt 
JFGDOI000000|12|12|20180328|707|850|190|0||0|85058838|0|||0||||||1|kritisch|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1|706|||0000|||1|0|||||||

Du siehst, auch mir ist eine leere Zelle nicht spectaculär genug.

Mein erster Ansatz war viel besser, mit sed - leider ein Scheitern auf ganzer Linie - keine Ahnung, was ich das verbastelt habe – ah, logisch, jetzt habe ich den Fehler gefunden:

1
2
3
4
5
6
7
8
sed -r 's/^(([^|]*\|){22})([0-9]{1,2}\|)(.*)/\1|-- --\4/' dpetest.txt 
JFGDOI000000|12|12|20180328|707|850|190|0||0|85058838|0|||0||||||1|||-- --|||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||
sdfsdf6205503762|Ddfsf|30|20180328|706|850|190|0||0|85058838|0|||0||||||1||706||||0000|||1|0|||||||

Das ersetzt (s:=substitute) in einem String, verankert am Zeilenanfang (^) Muster (...) derart, dass sie kein Pipesymbol enthalten [^|]* und von beliebiger Länge sein dürfen, inklusive leer, aber von einem Pipesymbol gefolgt werden müssen [^|]*\| (welches maskiert werden muss, da es sonst 'ODER' bedeuten will. Und von diesem Muster ([^|]*\|) suchen wir 22 Stück ([^|]*\|){22} und packen sie in Klammern, um sie später zu referenzieren (([^|]*\|){22}) wobei die äußere Klammer die erste, öffnende Klammer ist. Wenn das von 1-2 Ziffern gefolgt wird, die ihrerseits wieder ein Pipesymbol im Schlepptau haben, also keinesfalls 3 Ziffern, ([0-9]{1,2}\|) und dann kommt noch der poplige Rest (.*), dann schlagen wir zu, und ändern das in den ersten Ausdruck, gefolgt von etwas Spektakel, und dem vierten Ausdruck - der zweite ist ein Teilbereich des ersten, der dritte wird unterschlagen, (.*) ist also das vierte Klammernpaar: /\1|– –\4/' dpetest.txt

Treffen wir dieses Muster nicht an, tun wir nichts - Output = Input.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

In Haskell:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import Data.List
import Data.List.Split

delimiter = "|"

processCell (23, value) = if length value < 3 then "" else value
processCell (_, value)  = value

replace row = map processCell $ zip [1..] row

processLine line = intercalate delimiter $ replace $ splitOn delimiter line

process content = unlines $ map processLine $ lines content

main = interact process

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

1
2
3
4
5
6
7
import scala.io._

val zellen = Source.fromFile ("dpetest.txt").getLines ().mkString ("\n").split ("\n").map (_.split ("\\|"))
def diskriminateFeld23 (as: List[String]) : String = { 
    ((as.take (22) ::: {if (as(23).length < 3) "" else as (23)} :: as.drop (23)).mkString ("|")) 
}
println (zellen.map (as => diskriminateFeld23 (as.toList)).mkString ("\n"))

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

Nach neumodisch funktional mal altmodisch imperativ (QBasic):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
DEFINT a-z
CONST delimiter$ = "|"

f = FREEFILE
OPEN "test.txt" FOR INPUT AS #f
DO UNTIL EOF(f)
  LINE INPUT #f, line$
  
  i = 0
  FOR k = 1 TO 22
    i = INSTR(i + 1, line$, delimiter$)
  NEXT
  j = INSTR(i + 1, line$, delimiter$)

  IF j - i - 1 < 3 THEN
    PRINT LEFT$(line$, i); MID$(line$, j)
  ELSE
    PRINT line$
  END IF
LOOP
CLOSE #f

Edit: Wem das immer noch zu modern ist (GW-BASIC):

1
2
3
4
5
6
10 DEFINT A-Z:DELIMITER$="|"
20 OPEN "test.txt" FOR INPUT AS #1
30 WHILE NOT EOF(1):LINE INPUT #1,L$:I=0
40 FOR K=1 TO 22:I=INSTR(I+1,L$,DELIMITER$):NEXT:J=INSTR(I+1,L$,DELIMITER$)
50 IF J-I-1<3 THEN PRINT LEFT$(L$,I);MID$(L$,J) ELSE PRINT L$
60 WEND:CLOSE#1

Edit2: Oder altmodisch und funktional mit vielen Klammern (Scheme-Dialekt Racket):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env racket
#lang racket
(define *delimiter* "|")
(define *column-index* 22)

(define (process-line line [column-index *column-index*])
  (let ([row (string-split line *delimiter* #:trim? #f)])
    (string-join (if (< (string-length (list-ref row column-index)) 3)
                     (list-set row column-index "")
                     row)
                 *delimiter*)))

(display-lines-to-file (map process-line (file->lines "test.txt"))
                       "test2.txt"
                       #:exists 'truncate)

(module+ test
  (require rackunit)
  (check-equal? (process-line "a|b|c" 1) "a||c")
  (check-equal? (process-line "a|xyz|c" 1) "a|xyz|c")
  (check-equal? (process-line "||" 1) "||"))
Antworten |