How to get integer with regular expression in kotlin? - regex

ViewModel
fun changeQty(textField: TextFieldValue) {
val temp1 = textField.text
Timber.d("textField: $temp1")
val temp2 = temp1.replace("[^\\d]".toRegex(), "")
Timber.d("temp2: $temp2")
_qty.value = textField.copy(temp2)
}
TextField
OutlinedTextField(
modifier = Modifier
.focusRequester(focusRequester = focusRequester)
.onFocusChanged {
if (it.isFocused) {
keyboardController?.show()
}
},
value = qty.copy(
text = qty.text.trim()
),
onValueChange = changeQty,
label = { Text(text = qtyHint) },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
save()
onDismiss()
}
)
)
Set KeyboardType.Number, it display 1,2,3,4,5,6,7,8,9 and , . - space.
I just want to get integer like -10 or 10 or 0.
But I type the , or . or -(not the front sign), it show as it is.
ex)
typing = -10---------
hope = -10
display = -10---------
I put regular expression in
val temp2 = temp1.replace("[^\\d]".toRegex(), "")
But, it doesn't seem to work.
How I can get only integer(also negative integer)?

Use this regex (?<=(\d|-))(\D+) to replace all non digit characters, except first -.
fun getIntegersFromString(input: String): String {
val pattern = Regex("(?<=(\\d|-))(\\D+)")
val formatted = pattern.replace(input, "")
return formatted
}
Check it here

Related

Compose desktop(JVM) BasicTextField, Korean input duplicating

I'm implementing a simple search input field on Compose desktop.
My code looks as below.
BasicTextField(
modifier = Modifier.align(Alignment.CenterVertically).onPreviewKeyEvent {
if(it.key == Key.Enter && it.type == KeyEventType.KeyDown){
println("enter down: $textFieldState")
true
}else {
false
}
},
value = textFieldState,
onValueChange = { input ->
textFieldState = input
},
textStyle = TextStyle(
fontSize = 14.sp,
textAlign = TextAlign.Start,
fontWeight = FontWeight.Normal,
fontFamily = NotoSans,
color = Color.Black
),
maxLines = 1,
decorationBox = { innerTextField ->
Row(modifier = Modifier.fillMaxWidth()) {
if (textFieldState.isEmpty()) {
Text(
text = "Search with user name.",
fontSize = 14.sp,
color = Color(0xFF909ba9),
textAlign = TextAlign.Start,
fontWeight = FontWeight.Normal,
fontFamily = NotoSans,
modifier = Modifier.fillMaxWidth()
.align(Alignment.CenterVertically),
)
}
}
innerTextField()
}
)
This code will create a textfield which has 1 max lines.
It works without any problem on english inputs.
But when I type in Korean inputs, keys such as space, enter, or even numbers will duplicate the last Korean character. For example, in english, if I type in H, I, !,
it will be HII!.
Is there some locale settings that can be done to the textField?
I found no working solution in here or in the Compose multiplatform git issue page. I found a workaround using SwingPanel and JTextField.
SwingPanel(background = Color(0xFFf5f6f6), modifier = Modifier.fillMaxSize(), factory = {
//Some JTextfield I've obtaines from stackoverflow to show place holder text.
//Can be replaced to JTextField(columnCount:Int)
HintTextField("Enter in name",1).apply {
background = java.awt.Color(0xf5, 0xf6, 0xf6)
border = null
}
}, update = {
//SimpleDocumentListener is an implementation of DocumentListener.
//Which means it can be replaced by it.
it.document.addDocumentListener(object : SimpleDocumentListener{
override fun update(e: DocumentEvent) {
try{
val text = it.text
textFieldState = text
} catch(e : Exception) {
e.printStackTrace()
}
}
})
//I need an enter key to trigger some search logics.
//textFieldState seems to print the value as I intended
it.addKeyListener(object : KeyAdapter(){
override fun keyPressed(e: KeyEvent?) {
if(e?.keyCode == KeyEvent.VK_ENTER){
println("ENTER : $textFieldState")
}
}
})
})
Really hope the compose multiplatform team comes up with a better solution.

Is there a way to find an element in a list and delete items after it that are of a specific type without using indicies?

I have a project that needs me to remove items if one of the properties of the item I'm trying to find within the list is true. Just so it's easier understand the project I am pasting all code needed to understand it below.
fun main() {
val acct1 = AccountId(72)
val calendars = mutableListOf<CalendarDrawerCalendarItem>()
val calendars2 = mutableListOf<CalendarDrawerCalendarItem>()
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 3),"toast", true)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 4), "chicken", false)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 5), "pizza", true)))
calendars2.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 1), "bagel", true)))
// These are example calls to collapse
collapse(calendars, CalendarDrawerGroupItem(true, CalendarGroupDescriptor( acct1, "My Calendars")))
collapse(calendars2, CalendarDrawerGroupItem(false, CalendarGroupDescriptor(acct1, "Group Calendars")))
}
fun collapse(calendars: List<CalendarDrawerListItem>, group: CalendarDrawerGroupItem): List<CalendarDrawerListItem> {
val collapsedResults = mutableListOf<CalendarDrawerListItem>()
val findGroupGiven = group
collapsedResults.addAll(calendars)
if (collapsedResults.contains(findGroupGiven)) {
group.collapsed = true
// logic for deleting items here
}
return collapsedResults
}
I'll also put the classes so you can see how they're defined
data class AccountId(
val accountId: Int
)
data class CalendarId(
val accountId: AccountId,
val calendarId: Int)
data class CalendarDescriptor(
val accountId: AccountId,
val calendarId: CalendarId,
val name: String,
val isGroupCalendar: Boolean
)
data class CalendarGroupDescriptor(
val accountId: AccountId,
val name: String,
)
sealed class CalendarDrawerListItem
data class CalendarDrawerGroupItem(var collapsed: Boolean, val groupDescriptor: CalendarGroupDescriptor) : CalendarDrawerListItem()
data class CalendarDrawerCalendarItem(val calendarDescriptor: CalendarDescriptor) : CalendarDrawerListItem()
The first step I have done is I must find the given group from the group variable, within calendars. (I did this with the contains() method). Next when I find the group I have to set its collapsed variable to true and any CalendarDrawerCalendarItems after it have to be deleted.
The input will look something like (the exact numbers and values are not the important part):
Input:
calendars:
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 1, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 2, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 3, isGroup = false))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
group: CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
The output should look something like this:
Output:
CDGroupItem(collapsed = true, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
Any group item that has its collapsed boolean set to true should have all calendar items deleted after it since its collapsed is set to true. Again the names and numbers are not super important. The collapsed bool is. How can I do this without hardcoding or using indicies?
Your example code doesn't use that input and output as-is so I can only give you a general example, but you could use a fold:
val result = calendars.fold(mutableListOf<CalendarDrawerListItem>()) { items, current ->
// basically 'is there a last item stored, and is it a group item, and is it collapsed'
val lastStoredIsCollapsed =
(items.lastOrNull() as? CalendarDrawerGroupItem)?.collapsed == true
if (current is CalendarDrawerCalendarItem && lastStoredIsCollapsed) items
else items.apply { add(current) }
}
It basically pipes out each item into a list, but if the last one it stored is a CalendarDrawerGroupItem with collapsed set to true, it drops drawer items. If the last one is a non-collapsed group item, it can store a drawer item, and that means the next drawer item will be stored (since the last item isn't a collapsed group)
edit: here's the for loop equivalent if it helps, with the full logic for when a calendar is not dropped (the logic in my other example is for whether it should be dropped, which can be condensed a bit):
// assuming 'calendars' is your list of items with 'collapsed' set appropriately
val result = mutableListOf<CalendarDrawerListItem)
for (calendar in calendars) {
val lastStored = result.lastOrNull()
when {
lastStored == null ->
result.add(calendar)
lastStored is CalendarDrawerGroupItem && !lastStored.collapsed ->
result.add(calendar)
lastStored is CalendarDrawerCalendarItem ->
result.add(calendar)
}
}
return result
If you're asking how to actually mutate your list so a collapsed property is set to true, that would be easy if the property was a var in your data class. Since it's a val you'll have to do something like this:
val calendarInputWithCollapsedSet = calendars.map { calendar ->
if ((calendar as? CalendarDrawerGroupItem)?.groupDescriptor == group.groupDescriptor)
calendar.copy(collapsed = true) else calendar
}
So if you find a matching group (you'll have to work out how to match them, I'm guessing) you transform it into a copy with its collapsed property set
And then you can run the fold or whatever on that new list.

Find and change cyrillic word with boundary in google scripts

The problem is that \b doesn't work with Russian and Ukrainian letters.
Here I try to find all matches of a word 'февраля' it the text, change them to tempword, then make it a link and change it back to 'февраля'.
function addLinks(word, siteurl) {
var id = 'doc\'s ID';
var doc = DocumentApp.openById(id);
var body = doc.getBody();
var tempword = 'ASDFDSGDDKDSL2';
var searchText = "\\b"+word+"\\b";
var element = body.findText(searchText);
console.log(element);
while (element) {
var start = element.getStartOffset();
var text = element.getElement().asText();
text.replaceText(searchText, tempword);
text.setLinkUrl(start, start + tempword.length - 1, siteurl);
element = body.findText(searchText);
}
body.replaceText(tempword, word);
}
addLinks('февраля', 'example.com');
It works as it should, if I change Russian word 'февраля' to English 'february'.
addLinks('february', 'example.com');
I need regular expression, because if I just look for 'февраля' script will apply it to other words like 'февралям', 'февралями' etc.
So, it is a question, how to make it work.
Mistake "Exception: Invalid regular expression pattern" occurs with this code:
var searchText = "(?<=[\\s,.:;\"']|^)"+word+"(?=[\\s,.:;\"']|$)";
or this:
var searchText = "(^|\s)"+word+"(?=\s|$)";
and some other.
Here is my solution:
function main() {
addLinks('февраля', 'example.com');
}
function addLinks(word, url) {
var doc = DocumentApp.getActiveDocument();
var pgfs = doc.getParagraphs();
var bound = '[^А-яЁё]'; // any letter except Russian one
var patterns = [
{regex: bound + word + bound, start: 1, end: 1}, // word inside of line
{regex: '^' + word + bound, start: 0, end: 1}, // word at the start
{regex: bound + word + '$', start: 1, end: 0}, // word at the end
{regex: '^' + word + '$', start: 0, end: 0} // word = line
];
for (var pgf of pgfs) for (var pattern of patterns) {
var location = pgf.findText(pattern.regex);
while (location) {
var start = location.getStartOffset() + pattern.start;
var end = location.getEndOffsetInclusive() - pattern.end;
pgf.editAsText().setLinkUrl(start, end, url);
location = pgf.findText(pattern.regex, location);
}
}
}
Test output:
It handles well the word placed at the start or at the end of the line (or both). And it gives no the weird error message.

Regular expression to extract Words inside nested parentheses

im looking for the regexp that make able to do this tasks
message Body Input: Test1 (Test2) (test3) (ti,ab(text(text here(possible text)text(possible text(more text))))) end (text)
the result that i want Result: (text(text here(possible text)text(possible text(more text))))
I want to collect everything that is inside ti,ab(................)
var messageBody = message.getPlainBody()
var ssFile = DriveApp.getFileById(id);
DriveApp.getFolderById(folder.getId()).addFile(ssFile);
var ss = SpreadsheetApp.open(ssFile);
var sheet = ss.getSheets()[0];
sheet.insertColumnAfter(sheet.getLastColumn());
SpreadsheetApp.flush();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn() + 1)
var values = range.getValues();
values[0][sheet.getLastColumn()] = "Search Strategy";
for (var i = 1; i < values.length; i++) {
//here my Regexp
var y = messageBody.match(/\((ti,ab.*)\)/ig);
if (y);
values[i][values[i].length - 1] = y.toString();
range.setValues(values);
The only solution you may use here is to extract all substrings inside parentheses and then filter them to get all those that start with ti,ab:
var a = [], r = [], result;
var txt = "Test1 (Test2) (test3) (ti,ab(text(text here(possible text)text(possible text(more text))))) end (text)";
for(var i=0; i < txt.length; i++){
if(txt.charAt(i) == '(') {
a.push(i);
}
if(txt.charAt(i) == ')') {
r.push(txt.substring(a.pop()+1,i));
}
}
result = r.filter(function(x) { return /^ti,ab\(/.test(x); })
.map(function(y) {return y.substring(6,y.length-1);})
console.log(result);
The nested parentheses function is borrowed from Nested parentheses get string one by one. The /^ti,ab\(/ regex matches ti,ab( at the start of the string.
The above solution allows extracting nested parentheses inside nested parentheses. If you do not need it, use
var txt = "Test1 (Test2) ((ti,ab(text(text here))) AND ab(test3) Near Ti(test4) NOT ti,ab,su(test5) NOT su(Test6))";
var start=0, r = [], level=0;
for (var j = 0; j < txt.length; j++) {
if (txt.charAt(j) == '(') {
if (level === 0) start=j;
++level;
}
if (txt.charAt(j) == ')') {
if (level > 0) {
--level;
}
if (level === 0) {
r.push(txt.substring(start, j+1));
}
}
}
console.log("r: ", r);
var rx = "\\b(?:ti|ab|su)(?:,(ti|ab|su))*\\(";
var result = r.filter(function(y) { return new RegExp(rx, "i").test(y); })
.map(function(x) {
return x.replace(new RegExp(rx, "ig"), '(')
});
console.log("Result:",result);
The pattern used to filter and remove the unnecessary words
\b(?:ti|ab|su)(?:,(ti|ab|su))*\(
Details
\b - a word boundary
(?:ti|ab|su) - 1 of the alternatives,
(?:,(ti|ab|su))* - 0 or more repetitions of , followed with 1 of the 3 alternatives
\( - a (.
The match is replaced with ( to restore it in the match.

how we find and replace array dictionary value in swift 3

My array has this dictionary I want to find and replace where dictionary h
attendance = "" and attendance = "A" and replace with attendance = "P"
I am using this:
checkedArray = [[String : AnyObject]]()
let index = find(checkedArray) { $0["attendance"] == "P" }
if let index = index {
checkedArray[index] = newDictionary
}
// Do any additional setup after loading the view.
}
func find<C: CollectionType>(collection: C, predicate: (C.Generator.Element) -> Bool) -> C.Index? {
for index in collection.startIndex ..< collection.endIndex {
if predicate(collection[index]) {
return index
}
}
return nil
}
[
{"studentID":"12","name":"panky","roll":"","attendance":"P"},
{"studentID":"14","name":"a","roll":"","attendance":""},
{"studentID":"4","name":"akshay","roll":"1","attendance":"E"},
{"studentID":"6","name":"anki","roll":"11","attendance":"P"},
{"studentID":"1","name":"mohit","roll":"2","attendance":"M"},
{"studentID":"5","name":"yogi","roll":"22","attendance":"L"},
{"studentID":"3","name":"Neha","roll":"3","attendance":"A"}
]
let dic: [[String : Any]] = [
["studentID":"12","name":"panky","roll":"","attendance":"P"],
["studentID":"14","name":"a","roll":"","attendance":""],
["studentID":"4","name":"akshay","roll":"1","attendance":"E"],
["studentID":"6","name":"anki","roll":"11","attendance":"P"],
["studentID":"1","name":"mohit","roll":"2","attendance":"M"],
["studentID":"5","name":"yogi","roll":"22","attendance":"L"],
["studentID":"3","name":"Neha","roll":"3","attendance":"A"]
]
let result : [Any] = dic.map { dictionary in
var dict = dictionary
if let attendance = dict["attendance"] as? String, attendance == "" || attendance == "A" {
dict["attendance"] = "P"
}
return dict
}