I have the following expression
IIF(LABELS.NAME==PARTS.ANAME,IIF(!EMPTY(PARTS.BNAME),"B NAME IS:"+PARTS.BNAME,""),"A NAME IS :" +PARTS.ANAME)
The expression check two fields for matching words for example
field LABELS.NAME: hello
field PARTS.BNAME: hello
field PARTS.ANAME: value
if a match is found it will print "B Name IS: " + the value of BNAME else it will print whatever value is in ANAME.
I am trying to do something so that it will still find a match if
1- the word hello is in BNAME but upper case or mix upper and lower case, and if there is another word or more next to it so for example
field LABELS.NAME: hello world!
field PARTS.BNAME: hello
then it's a match!
or vice versa
field LABELS.NAME: hello
field PARTS.BNAME: hello world
your expression and your explanation are not clear nor correct. Let's break down your expression:
IF LABELS.NAME is an EXACT match of PARTS.ANAME:
Select "B NAME IS:"+PARTS.BNAME or if blank select ""
ELSE:
"A NAME IS :" +PARTS.ANAME
Basically, you are saying if name and aname match, select bname.
As for your explanation, it is unclear whether you are checking for one-word match only, or each word matching?
Try running this and see if it is more in line with what you are looking for:
CLEAR
CREATE CURSOR labels (name c(20))
INSERT INTO labels VALUES ("hello WORLD!")
INSERT INTO labels VALUES ("hello")
CREATE CURSOR parts (aname c(20), bname c(20))
INSERT INTO parts VALUES ("aname value","hello")
INSERT INTO parts VALUES ("aname value2","hello world")
GOTO TOP IN labels
GOTO TOP IN parts
=domatch()
SKIP IN parts
=domatch()
SKIP IN labels
SKIP -1 IN parts
=domatch()
SKIP IN parts
=domatch()
FUNCTION domatch()
? "LABELS Record " + TRANSFORM(RECNO("labels")) + " " + "PARTS Record " + TRANSFORM(RECNO("parts"))
? "LABELS.Name:" + labels.name
? "PARTS.Aname:" + parts.aname
? "PARTS.Bname:" + parts.bname
? "---------------------------"
? IIF(ALLTRIM(UPPER(labels.name)) $ UPPER(parts.bname),"B NAME IS: " + parts.bname + " (name is contained in labels bname)", "A NAME IS: " + parts.aname+ " (NO match, here's aname value)")
? IIF(ALLTRIM(UPPER(parts.bname)) $ UPPER(labels.name),"B NAME IS: " + parts.bname + " (bname is contained in labels name)", "A NAME IS: " + parts.aname+ " (NO match, here's aname value)")
?
The key to the above example is the use of:
$ operator : cSearchFor $ cSearchIn
ALLTRIM() : left and right trim
UPPER() : convert both strings to uppercase for matching
HTH
Your problem is not very clear.
Likely it is not something that you can solve using operators like $, and functions like trim(), upper() etc. BUT it may be and you might have failed to explain it clearly. For eaxample, if BName is "Chello" and Labels have "Hello" or "Hello World" is it a match for BName? I thought it is not. "Hello" is a match but "Chello" is not, right? Unfortunately you didn't give any sample data.
The solution sounds to be scary, using VFP and be very slow. Hoping your parts and labels data do not have much data in them, it could be solved with xbase + alines or using regular expressions.
Although this looks very ugly and would be slow, I think the original design of data is ugly.
Create Cursor labels (Name c(20))
Insert Into labels Values ("hello WORLD!")
Insert Into labels Values ("HellO")
Insert Into labels Values ("way")
Create Cursor parts (Id i Autoinc, aname c(20), bname c(20))
Insert Into parts (aname, bname) Values ("aname value1","hello")
Insert Into parts (aname, bname) Values ("aname value2","hello world")
Insert Into parts (aname, bname) Values ("aname value3","HeLlo world")
Insert Into parts (aname, bname) Values ("aname value4","Hello World")
Insert Into parts (aname, bname) Values ("aname value5","Hello There")
Insert Into parts (aname, bname) Values ("aname value6","My World")
Insert Into parts (aname, bname) Values ("aname value7","World Fair")
Insert Into parts (aname, bname) Values ("aname value8","Two way")
Insert Into parts (aname, bname) Values ("aname value9","Chello")
Insert Into parts (aname, bname) Values ("aname value10","worlds")
Local oRegEx
oRegEx = Createobject("VBScript.RegExp")
oRegEx.IgnoreCase = .T.
oRegEx.Global = .T.
Select p.ID, p.AName, p.BName, ;
Cast(Iif(IsNull(tmp.Id), 'AName is:' + AName, 'BName is:' + BName) as c(30)) dummy ;
from parts p ;
left join ;
(Select distinct p2.ID from parts p2 ;
inner join labels lb ;
on IsSpecialMatch(m.oRegEx, p2.bname, lb.Name)) tmp ;
on tmp.Id = p.Id
Procedure IsSpecialMatch(toRX, tcValue1, tcValue2)
Local IsMatch
toRX.Pattern = '\b'+Trim(m.tcValue1)+'\b'
IsMatch = toRX.Test( m.tcValue2 )
If !IsMatch
toRX.Pattern = '\b'+Trim(m.tcValue2)+'\b'
IsMatch = toRX.Test( m.tcValue1 )
Endif
Return m.IsMatch
Endproc
Related
I'm currently transforming my survey results for analysis. The survey program I used (limesurvey) automatically generates value labels, but I need to change the value the labels corresponds with. SPSS sadly doesn't do that automatically with the recode command, which only changes the values but doesn't change the value labels that correspond to it (They keep pointing at the old value which doesn't have any data entries anymore).
Basically I want to change the value labels from this:
Value labels before change
to this: Value labels after (Changing the labeled Values from A1,A2,A3,A4,A5 into 1,2,3,4,5)
And I don't just want to do it for a single variable, but dozens of variables. While this can actually be accomplished by the search/replace function via the User Interface of SPSS (that's actually how I did it in the example), I would like to do this via Syntax, so I don't have to handcraft every dataset and don't risk screwing up my data with typing mistakes.
Does anyone know how it can be done with Syntax? (Or alternatively some plugin)
So I've found a solution to my problem.
I did the recodes and the relabeling with Python.
BEGIN PROGRAM PYTHON3.
import spss, spssaux, re
sDict = spssaux.VariableDict() #Get a copy of the Variable Dictionary
infotext = "Variables processed: " # begin infotext
#Iterate through all variables (in the dictionary - all variables in this case)
for var in sDict:
#Only Adress variables which are of type String and have value labels.
if spss.GetVariableType(var.index) > 0 and var.ValueLabels != {} :
infotext += spss.GetVariableName(var.index) + ', ' #Add processed variable to infotext
#Begin Value Labels and Recode commands for active variable
commandlab = 'Value Labels ' + spss.GetVariableName(var.index) + ' '
commandrecode = 'Recode ' + spss.GetVariableName(var.index) + ' '
#commandalter = 'Alter Type ' + spss.GetVariableName(var.index) + '(f2).'
#Open entry for each value of valuelabels
for key,val in var.ValueLabels.items():
newkey = re.findall(r'\d+', key)[0] #Get first number in key (value of label)
newkey = re.sub(r'0+(.+)', r'\1', newkey) #Cut leading zeros from number
#Add entry to recode and Value labels command:
commandlab = commandlab + newkey + ' ' + '"' + val + '"' + ' '
commandrecode = commandrecode + '("' + key + '"="' + newkey + '") '
#Complete commands for SPSS:
commandlab = commandlab + '.'
commandrecode = commandrecode + '.\n Execute.'
#Execute recode and relabel.
spss.Submit(commandlab)
spss.Submit(commandrecode)
#spss.Submit(commandalter)
#Print Infos
print(infotext)
print("Warning: Only Values with value labels have been recoded. Please check your dataset to make sure all entries have been affected.")
end program.
Basically this program is finding all string variables with value labels, gets the numbers from the value/key and recodes and relabels the variables. It can also automatically turn all variables numeric, but I wouldn't recommend doing that without checking all values got converted first. In my case I merged several datasets and one variable had a value without label as a result.
Does anyone know how to get the values (or frequencies) of a variable? If possible, I'd like to catch that problem by doing the recode independent of the value labels.
I want to remove extra spaces from the text, i referenced the code from the internet as below:
(text as text)=>
let
x = Text.Split(text," "),
y = Text.Select(x,each _<>""),
z = Text.Combine(y," ")
in
z
when i apply this function for my data , it show the error is "Expression.Error: We cannot convert a value of type List to type Text." , my column is definitely is text format already , i don't know root of the issue, could you please help look ?
my data is very simple, like below:
You can use below code as a custom function:
(text as text, optional char_to_trim as text) =>
let
char = if char_to_trim = null then " " else char_to_trim,
split = Text.Split(text, char),
removeblanks = List.Select(split, each _ <> ""),
result=Text.Combine(removeblanks, char)
in
result
Split the text values in a column based on the data type of the first character in each record.
I need to have the new (custom) column return the text before the first " " delimiter if the first character of the text is a number, otherwise return "0,".
If Value.Is(Text.Start([ConsumerAddress],1), type number) Then
Text.BeforeDelimiter([ConsumerAddress]," ") else "0,"
I need to have the new (custom) column return the text before the first " " delimiter if the first character of the text is a number, otherwise return "0,".
I don't think Value.Is is quite what you want. I would recommend a try otherwise construction along with Number.FromText like this:
= Table.AddColumn(#"Previous Step", "Custom",
each try Number.FromText(Text.BeforeDelimiter([ConsumerAddress], " "))
otherwise 0
)
If the text before the first space can be converted to a number, then that's what you get. If it can't the Number.FromText throws an error and you get the 0 from the otherwise specification.
Edit: If you want the criterion for the first character only, try this:
= Table.AddColumn(#"Previous Step", "Custom",
each if (try Number.FromText(Text.Start([ConsumerAddress], 1)) otherwise 0) <> 0
then Text.BeforeDelimiter([ConsumerAddress], " ")
else "0"
)
This will return "12b" from "12b Maple St" whereas the first version would return 0 since "12b" can't be converted into a number.
How can I, using M-language, replace specific words in a string with other specific words that are specified in a table?
See my example data:
Source code:
let
someTable = Table.FromColumns({{"aa &bb &cc dd","&ee ff &gg hh &ii"}, {Table.FromColumns({{"&bb","&cc"}, {"ReplacementForbb", "ccReplacement"}},{"StringToFind", "ReplaceWith"}), Table.FromColumns({{"&ee", "&gg","&ii"}, {"OtherReplacementForee", "SomeReplacementForgg", "Replacingii"}},{"StringToFind", "ReplaceWith"})}, {"aa ReplacementForbb ccReplacement dd","OtherReplacementForee ff SomeReplacementForgg hh Replacingii"}},{"OriginalString", "Replacements", "WantedResult"})
in
someTable
This is a neat question. You can do this with some table and list M functions as a custom column like this:
= Text.Combine(
List.ReplaceMatchingItems(
Text.Split([OriginalString], " "),
List.Transform(Table.ToList([Replacements]),
each Text.Split(_,",")
)
),
" ")
I'll walk through how this works using the first row as an example.
The [OriginalString] is "aa &bb &cc dd" and we use Text.Split to convert it to a list.
"aa &bb &cc dd" --Text.Split--> {"aa", "&bb", "&cc", "dd"}
Now we need to work on the [Replacements] table and convert it into a list of lists. It starts out:
StringToFind ReplaceWith
------------------------------
&bb ReplacementForbb
&bb ccReplacement
Using Table.ToList this becomes a two element list (since the table had two rows).
{"&bb,ReplacementForbb","&cc,ccReplacement"}
Using Text.Split on the comma, we can transform each element into a list to get
{{"&bb","ReplacementForbb"},{"&cc","ccReplacement"}}
which is the form we need for the List.ReplaceMatchingItems function.
List.ReplaceMatchingItems(
{"aa", "&bb", "&cc", "dd"},
{{"&bb","ReplacementForbb"},{"&cc","ccReplacement"}}
)
This does the replacement and returns the list
{"aa","ReplacementForbb","ccReplacement","dd"}
Finally, we use Text.Combine to concatenate the list above into a single string.
"aa ReplacementForbb ccReplacement dd"
hello i have i want to do something like this.
i have 4 rows with unique id 1,2,3,4 all four rows contains some string like
option1,option2,option3,option4
now i want to add "a ) " to the option1, "b ) " to the option2 and so on so is there a way i can do this with a query.currently i am adding these to a lots of rows manually
It's not clear exactly by what logic you want to select the letter to prepend to field somestring, but if for example it's a "Caesar's cypher" (1 gives 'a', 2 gives 'b' etc) based on the id field, as your question suggests, then this should work:
UPDATE sometable
SET somestring = (
substr('abcdefghijklmnopqrstuvwxyz', id, 1) ||
' ) ' || somestring)
WHERE id <= 26;
...for no more than 26 rows of course, since beyond that the logic must change and obviously we can't guess just how you want to extend it (use id modulo 26 + 1, use more characters than just lowercase letters, or ...?) since you give no clue on why you want to do this.