LesezeichenAbonnierenRSS-Feed abonnieren
Katrin1606
Fluorite | Level 6

Hallo zusammen,

 

ich sitze schon gefühlt schon seit Ewigkeiten vor folgendem Problem. Natürlich habe ich versucht mich zu belesen und herauszufinden wie ich es löse, jedoch vergebens 😞

 

Wie kann ich folgendes innerhalb einer Zelle gut leserlich trennen:

- Wörter die durch Sonderzeichen verbunden sind, z.B.: Brief/Post oder ERF!RSA oder SOMMER:WINTER

- Wörter die hintereinander ohne Leerzeichen geschrieben sind aber immer mit Großbuchstaben beginnen, z.B. PostWichtige

- Zahl und Buchstabe trennen (zuerst kommt die Zahl, dann das Wort, z.B. 225,00Freitext   oder 15.01.2021Freitext oder 2RSA:      

 

Es wäre mir eine große Hilfe wenn mir jemand helfen könnte. Wenn es einen data step gibt, der keine Makros verwendet, noch besser :).

 

Viele Grüße

Katrin

 

4 ANTWORTEN 4
Benno_Burkhart
Calcite | Level 5
Hi Katrin,
du könntest nach regulären Ausdrücken suchen.
Viele Grüße
Benno
 
data _null_;
     length TEXT TEIL1 TEIL2 $32767;
     /* Ad 1: Sonderzeichen */
     TEXT = 'Br3ief/Post';
     /* Finde regulaeren Ausdruck... Sonderzeichen */
     POSITION = prxmatch ('/\W/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 2);
     put TEXT= POSITION= TEIL1= TEIL2=;

     TEXT = 'ERF!RSA';
     /* Finde regulaeren Ausdruck... Sonderzeichen */
     POSITION = prxmatch ('/\W/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 2);
     put TEXT= POSITION= TEIL1= TEIL2=;

     TEXT = 'SOMMER:WINTER';
     /* Finde regulaeren Ausdruck... Sonderzeichen */
     POSITION = prxmatch ('/\W/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 2);
     put TEXT= POSITION= TEIL1= TEIL2=;

     TEXT = 'ERF/RSA';
     /* Finde regulaeren Ausdruck... Sonderzeichen */
     POSITION = prxmatch ('/\W/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 1);
     put TEXT= POSITION= TEIL1= TEIL2=;

     /* Ad 2: Grossbuchstabe */
     TEXT = 'PostWichtige';
     /* Finde regulaeren Ausdruck... Grossbuchstabe */
     POSITION = prxmatch ('/[A-Z]/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 1);
     put TEXT= POSITION= TEIL1= TEIL2=;
 
     /* Ad 3: Zahl */
     TEXT = '225,00Freitext';
     /* Finde regulaeren Ausdruck... Buchstaben */
     POSITION = prxmatch ('/[A-Za-z]/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 1);
     put TEXT= POSITION= TEIL1= TEIL2=;

     TEXT = '2RSA';
     POSITION = prxmatch ('/[A-Za-z]/', substr (TEXT, 2));
     TEIL1 = substr (TEXT, 1, POSITION);
     TEIL2 = substr (TEXT, POSITION + 1);
     put TEXT= POSITION= TEIL1= TEIL2=;
run;
DavidHD
SAS Employee

Hi @Katrin1606 ,

 

habe mal eine Lösung auf der Basis von RegEx und den SAS-Funktionen scan & count entwickelt. Für die erste beiden Fälle habe ich Lösungen entwickelt die mit beliebig vielen verbundenen "Wörtern" umgehen kann. Für den letzten Fall habe ich bisher noch keine Lösung die mit n Wörtern umgehen kann - solltest du das benötigen sag Bescheid. Zu RegEx in SAS empfehle ich immer das Cheat-Sheet. Der Code ist nicht wirklich kommentiert, ich hoffe er spricht für sich.

 

data work.aaa(drop=p1 p2 p3 c1 c2 i j l);
	length w1 w2 w3 $256.;
	* Sonderzeichen;
	str2 = "ERF!RSA";
	p2 = prxparse('/\W/');
	c2 = countw(str2, '', 'P') ;
	do j = 1 to c2;
		w2 = scan(str2, j, '', 'P');
		output;
	end;

	* camelCase-Worttrennung;
	str1 = "PostWichtigeTest";
	p1 = prxparse('/[A-Z]/');
	c1 = countw(str1, "", 'U');
	*w1 = substr(str1, 1, prxmatch(p1, substr(str1, 2)));
	do i = 1 to c1;
		if i = 1 then l = 1;
		w1 = substr(str1, l, prxmatch(p1, substr(str1, l + 1)));
		l = l + length(w1);
		output;
	end;

	* Zahlen-Worttrennung;
	str3 = "225,00Freitext";
	p3 = prxparse('/\d[A-Z]/');
	w3 = substr(str3, 1, prxmatch(p3, str3));
	output;
	w3 = substr(str3, prxmatch(p3, str3) + 1);
	output;
run;

Viele Grüße

David

 

FreelanceReinh
Jade | Level 19

Hallo Katrin,

 

ich denke auch, dass man hier mit regulären Ausdrücken arbeiten sollte. Wenn es das Ziel ist, den vorhandenen Text in einer Character-Variablen geeignet abzuändern, kann man dies direkt mit der PRXCHANGE-Funktion tun.

 

Beispiel:

/* Erzeugen von Beispieldaten */

data have;
input c $50.;
cards;
z.B. ein Brief/Post von heute/gestern
ERF!RSA
Katalog SOMMER:WINTER 2021
PostWichtige
EUR225,00Freitext
ab15.01.2021Freitext
100 kW
2RSA
c/o
30/100
Neu/Änderungen
TabelleÜbersicht
Schließung/Öffnung
Spaß+Ärger
;

/* Anwenden von vier Änderungsregeln */

data want;
set have;
c=prxchange('s/([[:alpha:]]{2})([[:punct:]])([[:alpha:]]{2})/$1 $2 $3/',-1,c);
c=prxchange('s/([a-zäöüß]{2})([A-ZÄÖÜ])/$1 $2/',-1,c);
c=prxchange('s/(\d)([[:alpha:]])/$1 $2/',-1,c);
c=prxchange('s/([[:alpha:]])(\d)/$1 $2/',-1,c);
run;

Die "vier Änderungsregeln" bedeuten:

  1. Sonderzeichen, an das beidseitig jeweils mindestens zwei Buchstaben angrenzen, mit Leerzeichen umgeben.
  2. Leerzeichen nach mindestens zwei Kleinbuchstaben einfügen, wenn sich ein Großbuchstabe anschließt.
  3. Ziffer von Buchstabe durch Leerzeichen trennen.
  4. Dito in umgekehrter Reihenfolge.

Die Regeln werden jeweils "so oft wie möglich" (zweites Argument -1) angewandt.

 

Wenn noch Verfeinerungen oder Ergänzungen der Regeln nötig werden, kann man die regulären Ausdrücke sicherlich nachjustieren oder weitere hinzufügen.

 

DavePrinsloo
Pyrite | Level 9

REGex ist sicherlich sehr mächtig, abder ich bevorzüge die bewährte Functionen weil das Lesen für mich einfacher ist.

Was nicht für mich klar ist, aber ich have die trennende Sonderzeichen beibehalten.   Und kann auch Komma und Punkt als Trennzeichen vorkommen (Also, nicht nur in Zahlen).

 

data test;
input have $char30.;
length = length(have);
/* Position Zahl vorne - Finde erste Zeichen,  kein Zahl und auch nicht , oder .*/
split_pos_zahl=findc(have,'.,','DK');
/* Position Sonderzeichen Finde erste nicht-alphabetisch Zeichen */
split_pos_sonder = findc(have,'ÄÖÜäöüß','AK');
/* Gross/klein : Erste Grosszeichen, ignoriere 1. */
split_pos_gross = findc(have,'ÄEÖÜ','U',2);
if 1 < split_pos_zahl < length then best_pos = split_pos_zahl;
else if 1 < split_pos_sonder < length then best_pos = split_pos_sonder;
else if 1 < split_pos_gross < length then best_pos = split_pos_gross;
if Best_pos > 1 then want = substrn(have,1,best_pos-1)||' '||substrn(have,best_pos);  

cards;
Brief/Post
ERF!RSA
SOMMER:Winter
PostWichtige
225,00Freitext
15.01.2021Freitext
2RSA:
;
run;

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

Diskussionsstatistiken
  • 4 Antworten
  • 2692 Aufrufe
  • 2 Kudos
  • 5 in Unterhaltung