Skip to main content
Solved

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


Forum|alt.badge.img

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

 

 

Best answer by takashi

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"]]
}
View original
Did this help you find an answer to your question?

11 replies

david_r
Celebrity
  • February 26, 2018
There should be a bagde of honor for everybody that submits a question here that is so well explained! :-)

takashi
Influencer
  • Best Answer
  • February 26, 2018

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"]]
}

Forum|alt.badge.img
  • Author
  • February 26, 2018
takashi wrote:

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!

 


Forum|alt.badge.img
  • Author
  • February 26, 2018
takashi wrote:

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.

takashi
Influencer
  • February 26, 2018
edhere wrote:
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.

 

 


takashi
Influencer
  • February 26, 2018
takashi wrote:

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(' '));

Forum|alt.badge.img
  • December 5, 2019
takashi wrote:
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?


ebygomm
Influencer
Forum|alt.badge.img+33
  • Influencer
  • December 5, 2019

@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


Forum|alt.badge.img
  • December 9, 2019
ebygomm wrote:

@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.

 


tomjerry.vl
Forum|alt.badge.img

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.


jovitaatsafe
Safer
Forum|alt.badge.img+11
bazooka wrote:

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!


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings