如何从Flutter中的字符串中整体删除/检测任何表情符号?

时间:2019-05-14 14:01:17

标签: dart flutter

我想从Flutter(或Dart)中的字符串模拟键盘退格键删除事件。像这样:

String str = "hello你们‍‍"
myBackspace(str) // will return "hello你们"
myBackspace(str) // will return "hello你们"
myBackspace(str) // will return "hello你们"
myBackspace(str) // will return "hello你"
myBackspace(str) // will return "hello"
myBackspace(str) // will return "hello"
myBackspace(str) // will return "hell"

非常感谢。

注意:该问题的标题和描述与原始帖子相比有很大变化。

8 个答案:

答案 0 :(得分:2)

首先,让我们了解一些定义。根据{{​​3}}页:

  1. 字节:8位。 Unicode字符串将在内存或存储中占用的字节数取决于编码。
  2. 代码单位:可用于在文本编码中表示单个单位的最小位组合。例如,UTF-8中的1个代码单位将是1个字节,UTF-16中的2个字节,在UTF-32中的4个字节。
  3. 代码点[或符文]:Unicode字符。 Unicode空间上的单个整数值(来自U + 0000-U + 10FFFF)。
  4. 字素簇:用户感知的单个字符。 1个字素簇由几个代码点组成。

使用substring删除最后一个字符时,实际上是在删除最后一个代码单元。如果您运行print(newStr.codeUnits)print(str.codeUnits),则会看到128512符与代码单元5535756832的联合等效,因此{ {1}}实际上是有效的,但是在没有另一个代码单元的“帮助”的情况下不代表任何内容。

实际上,当您的字符串中包含非ASCII字符(例如表情符号或阿拉伯字母)时,您不想使用55357。它永远都行不通。您要做的是删除最后一个字素簇。这么简单:

substring

但是,Dart尚不支持此功能。关于这一点,存在几个问题。其中一些: this
https://github.com/dart-lang/language/issues/34

这种缺乏支持的接缝会导致其他一些问题,例如您提到的问题和该问题: https://github.com/dart-lang/language/issues/49

答案 1 :(得分:2)

此答案仍然有问题

由于dart不提供数据类型“ Grapheme Cluster”,因此我尝试使用方法通道使用kotlin进行此操作:

第1步:创建一个新的“ Flutter插件”项目,将其命名为“ gmc01”,将自动创建2个文件,即“ gmc01.dart”和“ main.dart”。

第2步:将gmc01.dart中的代码替换为以下内容:

import 'dart:async';

import 'package:flutter/services.dart';

class Gmc01 {
  static const MethodChannel _channel =
      const MethodChannel('gmc01');

  static Future<String> removeLastGMC(String strOriginal) async {
    final String version = await _channel.invokeMethod('removeLastGMC', strOriginal);
    return version;
  }
}

步骤3:将main.dart中的代码替换为以下内容:

import 'package:gmc01/gmc01.dart';

void main() async {
  String strTemp = '12345678我们5你‍‍';
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
  strTemp = await Gmc01.removeLastGMC(strTemp);
  print(strTemp);
}

第4步:在android / build.gradle中,将minSdkVersion从16更改为24。

步骤5:在example / android / app / build.gradle中,将minSdkVersion从16更改为24。

步骤6:单击文件->打开,选择gmc01-> android,然后单击“确定”,将打开插件的kotlin部分(在另一个窗口中)。

第7步:用以下代码替换Gmc01Plugin.kt中的代码:(用您自己的软件包名称替换第一行)

package com.example.gmc01   // replace the left with your own package name

import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import android.icu.text.BreakIterator



class Gmc01Plugin: MethodCallHandler {
  companion object {
    @JvmStatic
    fun registerWith(registrar: Registrar) {
      val channel = MethodChannel(registrar.messenger(), gmc01)
      channel.setMethodCallHandler(Gmc01Plugin())
    }
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    var strArg: String
    strArg = call.arguments.toString()
    var boundary = BreakIterator.getWordInstance()
    boundary.setText(strArg);
    when (call.method) {
      removeLastGMC -> {
        result.success(removeLastGMC(boundary, strArg))
      }
      else -> {
        result.notImplemented()
      }
    }
  }

  fun removeLastGMC(boundary: BreakIterator, source: String):String {
    val end = boundary.last()
    val start = boundary.previous()
    return source.substring(0, start)
  }
}

第8步:返回到插件窗口,然后单击“运行”。

这是控制台中的输出:

I/flutter (22855): 12345678我们5你
I/flutter (22855): 12345678我们5你
I/flutter (22855): 12345678我们5
I/flutter (22855): 12345678我们5
I/flutter (22855): 12345678我们
I/flutter (22855): 12345678
I/flutter (22855): 

如您所见,正确删除了“家庭表情符号”,“面部表情符号”和“国家国旗”表情符号,但是使用单个removeLastGMC删除了中文2个字符“我们”和数字“ 12345678”,因此仍然需要弄清楚如何区分中文双字节字符/英文字符/表情符号。

顺便说一句,我不知道该怎么做Swift部分,有人可以帮忙吗?

答案 2 :(得分:1)

代码不起作用

代码无法正常运行。我只是放在这里供参考。

审判1

  • 问题:无法正确处理‍‍
String myBackspace(String str) {
  Runes strRunes = str.runes;
  str = String.fromCharCodes(strRunes, 0, strRunes.length - 1);
  print(str);
  return str;
}

审判2

  • 问题:无法正确处理连接的表情符号序列‍‍

基于link

String myBackspace(String str) {
  int i = 0;
  while (str.length > 0) {
    i++;
    int removedCharCode = str.codeUnitAt(str.length - 1);
    if (isWellFormattedUTF16(removedCharCode)) break;
    str = str.substring(0, str.length - 1);
  }
  if (i == 1) str = str.substring(0, str.length - 1);
  print(str);
  return str;
}

bool isWellFormattedUTF16(int charCode) {
  int surrogateLeadingStart = 0xD800;
  int surrogateLeadingEnd = 0xDBFF;
  int surrogateTrailingStart = 0xDC00;
  int surrogateTrailingEnd = 0xDFFF;
  if (!(charCode >= surrogateLeadingStart && charCode <= surrogateLeadingEnd) && 
      !(charCode >= surrogateTrailingStart && charCode <=  surrogateTrailingEnd)) return true;
  return false;
}

答案 3 :(得分:1)

如果有人需要简单的解决方案从字符串中删除表情符号,请尝试此操作。

String str = "hello??你们???‍?‍?"İ 
    final RegExp REGEX_EMOJI = RegExp(r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])');
    if(str.contains(REGEX_EMOJI)){
       str = str.replaceAll(REGEX_EMOJI,'');
     }

答案 4 :(得分:1)

String formatText(String str) {

final RegExp regExp = RegExp(r'(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])');

if(str.contains(regExp)){
  str = str.replaceAll(regExp,'');
}

return str; }

例如:转到https://dartpad.dev/进行测试:

String str =“ ThaiKV受け行くけどよね??????” => ThaiKV受け行くけどよね

答案 5 :(得分:1)

With RegExp and replaceAll:

 final regex = RegExp(
 "(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000- 
 \udfff]|\ud83e[\ud000-\udfff])");

 final textReplace = String.replaceAll(regex, '');

答案 6 :(得分:0)

您要检查的内容有点不清楚。我建议您从子字符串中删除-1,因为它会破坏表情符号的代码片段

 void main() { 
   var str = "abc";
   var newStr = str.substring(0, str.length); // i removed it here
   print(newStr);
   print(newStr.runes);
   print(str.runes);
 }

这将给出

的输出
abc
(97, 98, 99, 128512)
(97, 98, 99, 128512)

经过https://dartpad.dartlang.org/

的测试

答案 7 :(得分:0)

您可以执行类似这样的方法

bool isValid(String prevString, String newString){
  if (prevString == newString)
    return true;

  else return false; 
}

然后在键盘上使用onChange属性进行验证

TextField(
  onChanged: (text) {
    isValid(varYouHad ,text); //validate
  },
);