Solved

How to replace part of string based on keyword? (a bulk StringReplacer?)

  • 26 February 2018
  • 11 replies
  • 20 views

Badge

Hi all,

I have a list of POI names that I'd like to abbreviate using an a Excel file that contains the keywords.

 

I only like to abbreviate the words found in the string that match with the keywords - not the whole string.

Basically what a StringReplacer does, but in bulk.

Thanks,

 

Eduard

 

 

icon

Best answer by takashi 26 February 2018, 10:33

View original

11 replies

Userlevel 5
There should be a bagde of honor for everybody that submits a question here that is so well explained! :-)
Userlevel 3
Badge +17

I found two ways.

1. Decompose, replace words if necessary, re-construct the name.

0684Q00000ArLFtQAN.png

2. Use a Tcl command.

0684Q00000ArLFyQAN.png

proc replace {} {
    return [string map [FME_GetAttribute "_pair"] [FME_GetAttribute "POI_NAME"]]
}
Badge

I found two ways.

1. Decompose, replace words if necessary, re-construct the name.

0684Q00000ArLFtQAN.png

2. Use a Tcl command.

0684Q00000ArLFyQAN.png

proc replace {} {
    return [string map [FME_GetAttribute "_pair"] [FME_GetAttribute "POI_NAME"]]
}
Thanks for the fast response @takashi - I'll give it a try!

 

Badge

I found two ways.

1. Decompose, replace words if necessary, re-construct the name.

0684Q00000ArLFtQAN.png

2. Use a Tcl command.

0684Q00000ArLFyQAN.png

proc replace {} {
    return [string map [FME_GetAttribute "_pair"] [FME_GetAttribute "POI_NAME"]]
}
Hi @takashi,

 

 

Looking good!

 

Is there a way to make these transformers not case sensitive? E.g. "Museum" is abbreviated to "Mus." which is good, but "museum" is not affected.
Userlevel 3
Badge +17
Hi @takashi,

 

 

Looking good!

 

Is there a way to make these transformers not case sensitive? E.g. "Museum" is abbreviated to "Mus." which is good, but "museum" is not affected.
In the first solution, use the @LowerCase (or @UpperCase) function in the Join On parameter setting.

 

 

Userlevel 3
Badge +17

I found two ways.

1. Decompose, replace words if necessary, re-construct the name.

0684Q00000ArLFtQAN.png

2. Use a Tcl command.

0684Q00000ArLFyQAN.png

proc replace {} {
    return [string map [FME_GetAttribute "_pair"] [FME_GetAttribute "POI_NAME"]]
}
Another way. The JSONTemplater in the workflow below creates a dictionary looks like this, and the JavaScriptCaller creates the short name according to this dictionary.

 

{
   "washington" : "Wash.",
   "square" : "Sq.",
   "museum" : "Mus.",
   "street" : "St.",
   "church" : "Ch."
}

0684Q00000ArMLXQA3.png

JSONTemplater ROOT Template Expression:

 

{|
    fme:process-features("SUB")
|}
JSONTemplater SUB Template Expression:

 

{
    fn:lower-case(fme:get-attribute("FULL")) : fme:get-attribute("ABBR")
}
JavaScript Code:

 

var dict = JSON.parse(fme_get_attribute('_dictionary'));
var src = fme_get_attribute("POI_NAME").split(' ');
var dest = []
for (var i = 0; i < src.length; i++) {
    var abbr = dict[src[i].toLowerCase()];
    dest.push(abbr ? abbr : src[i]);
}
fme_set_attribute('POI_SHORT_NAME', dest.join(' '));
Badge
Another way. The JSONTemplater in the workflow below creates a dictionary looks like this, and the JavaScriptCaller creates the short name according to this dictionary.

 

{
   "washington" : "Wash.",
   "square" : "Sq.",
   "museum" : "Mus.",
   "street" : "St.",
   "church" : "Ch."
}

0684Q00000ArMLXQA3.png

JSONTemplater ROOT Template Expression:

 

{|
    fme:process-features("SUB")
|}
JSONTemplater SUB Template Expression:

 

{
    fn:lower-case(fme:get-attribute("FULL")) : fme:get-attribute("ABBR")
}
JavaScript Code:

 

var dict = JSON.parse(fme_get_attribute('_dictionary'));
var src = fme_get_attribute("POI_NAME").split(' ');
var dest = []
for (var i = 0; i < src.length; i++) {
    var abbr = dict[src[i].toLowerCase()];
    dest.push(abbr ? abbr : src[i]);
}
fme_set_attribute('POI_SHORT_NAME', dest.join(' '));

This seemed to be good solution for my problem, until I found out that JavaScriptCaller is deprecated. Is there replacement for this JavaScript code?

Userlevel 1
Badge +21

@bazooka You can do something with python

0684Q00000ArLFRQA3.png

import fme
import fmeobjects

def insert_abbreviations(feature):
    dictionary = dict(zip(feature.getAttribute('_list{}.FULL'),feature.getAttribute('_list{}.ABBR')))
    poi = feature.getAttribute('POI_NAME')
    words = poi.split()
    words = [dictionary.get(w.upper(),w) for w in words]
    feature.setAttribute("abbreviated"," ".join(words))

 

*There are more efficient ways to build the dictionary than feature merging the list, but this is the simplest to demonstrate

Badge

@bazooka You can do something with python

0684Q00000ArLFRQA3.png

import fme
import fmeobjects

def insert_abbreviations(feature):
    dictionary = dict(zip(feature.getAttribute('_list{}.FULL'),feature.getAttribute('_list{}.ABBR')))
    poi = feature.getAttribute('POI_NAME')
    words = poi.split()
    words = [dictionary.get(w.upper(),w) for w in words]
    feature.setAttribute("abbreviated"," ".join(words))

 

*There are more efficient ways to build the dictionary than feature merging the list, but this is the simplest to demonstrate

Thank you @ebygomm !

I am now 1 step closer to solution. In my case there are multiple words which needs to be changed. For example "Omena (Banaani-Appelsiini)" -> "Apple (Banana-Orange)". Now only 1st one is changed, in this case 'Omena' -> 'Apple' and the whole thing "Omena (Banaani-Appelsiini)" -> "Apple (Banaani-Appelsiini)". I don't have Python coding skills, so I don't know how to change code to solve this.

I also don't need uppercase. I tried to change

words = [dictionary.get(w.upper(),w) for w in words] 

not to use uppercase, but I was not successful.

 

Badge

if i have number of words like Network and Net i need to change Net as Pet but it changes Network also as Petwork like below

 

OriginalNeedWorking like thisNetworkNetworkPetworkNetPetPet

 

Note: need to replace number of Words at time like StringPairReplacer Transformer.

Userlevel 1
Badge +11

This seemed to be good solution for my problem, until I found out that JavaScriptCaller is deprecated. Is there replacement for this JavaScript code?

Hi @bazooka, It looks like Takashi proposed two different solutions here. Does the first one with the TclCaller work for you? That one doesn't seem to use the JavascripCaller. If that doesn't work for you, would you be able to post a new question and link this one to it for context?

I almost overlooked your new comment thinking that this Q&A was already resolved, so posting a new one will up the visibility of your question to get more useful answers! Thanks!

Reply